Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
26 / 26
100.00% covered (success)
100.00%
8 / 8
CRAP
100.00% covered (success)
100.00%
1 / 1
RootObject
100.00% covered (success)
100.00%
26 / 26
100.00% covered (success)
100.00%
8 / 8
9
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 parse
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
2
 setVersion
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setParentIndex
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setFormReferences
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 getVersion
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getParentIndex
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __toString
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2declare(strict_types=1);
3/**
4 * Pop PHP Framework (https://www.popphp.org/)
5 *
6 * @link       https://github.com/popphp/popphp-framework
7 * @author     Nick Sagona, III <nick@popphp.org>
8 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
9 * @license    https://www.popphp.org/license     New BSD License
10 */
11
12/**
13 * @namespace
14 */
15namespace Pop\Pdf\Build\PdfObject;
16
17/**
18 * Pdf root object class
19 *
20 * @category   Pop
21 * @package    Pop\Pdf
22 * @author     Nick Sagona, III <nick@popphp.org>
23 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
24 * @license    https://www.popphp.org/license     New BSD License
25 * @version    6.0.0
26 */
27class RootObject extends AbstractObject
28{
29
30    /**
31     * PDF version
32     * @var float
33     */
34    protected float $version = 1.7;
35
36    /**
37     * PDF root object index
38     * @var ?int
39     */
40    protected ?int $index = 1;
41
42    /**
43     * PDF root parent index
44     * @var int
45     */
46    protected int $parent = 2;
47
48    /**
49     * Constructor
50     *
51     * Instantiate a PDF root object.
52     *
53     * @param  int $index
54     */
55    public function __construct(int $index = 1)
56    {
57        $this->setIndex($index);
58        $this->setData("[{root_index}] 0 obj\n<<[{form_index}]/Pages [{parent_index}] 0 R/Type/Catalog>>\nendobj\n");
59    }
60
61    /**
62     * Parse a root object from a string
63     *
64     * @param  string $stream
65     * @return RootObject
66     */
67    public static function parse(string $stream): RootObject
68    {
69        $root = new self();
70
71        // Else, parse out any metadata and determine the root and parent object indices.
72        $root->setIndex((int)substr($stream, 0, strpos($stream, ' ')));
73        $stream = str_replace($root->getIndex() . ' 0 obj', '[{root_index}] 0 obj', $stream);
74
75        // Strip away any metadata
76        if (str_contains($stream, '/Metadata')) {
77            $metadata = substr($stream, strpos($stream, 'Metadata'));
78            $metadata = '/' . substr($metadata, 0, strpos($metadata, '/'));
79            $stream = str_replace($metadata, '', $stream);
80        }
81
82        // Determine the parent index.
83        $parent = substr($stream, (strpos($stream, '/Pages') + 6));
84        $parent = trim(substr($parent, 0, strpos($parent, '0 R')));
85        $root->setParentIndex((int)$parent);
86        $stream = str_replace('Pages ' . $root->getParentIndex() . ' 0 R', 'Pages [{parent_index}] 0 R', $stream);
87
88        // Set the root object parent index and the data.
89        $root->setData($stream . "\n");
90
91        return $root;
92    }
93
94    /**
95     * Set the root object version
96     *
97     * @param  float $version
98     * @return RootObject
99     */
100    public function setVersion(float $version): RootObject
101    {
102        $this->version = $version;
103        return $this;
104    }
105
106    /**
107     * Set the root object parent index
108     *
109     * @param  int $p
110     * @return RootObject
111     */
112    public function setParentIndex(int $p): RootObject
113    {
114        $this->parent = $p;
115        return $this;
116    }
117
118    /**
119     * Set the root object's AcroForm reference
120     *
121     * Per spec, /AcroForm must be a single indirect reference to the
122     * document's one form dictionary, not an array of references.
123     *
124     * @param  string $form
125     * @return RootObject
126     */
127    public function setFormReferences(string $form): RootObject
128    {
129        $data = str_replace('[{form_index}]', '/AcroForm ' . $form, $this->data);
130        $this->setData($data);
131        return $this;
132    }
133
134    /**
135     * Get the root object version
136     *
137     * @return float
138     */
139    public function getVersion(): float
140    {
141        return $this->version;
142    }
143
144    /**
145     * Get the root object parent index
146     *
147     * @return int
148     */
149    public function getParentIndex(): int
150    {
151        return $this->parent;
152    }
153
154    /**
155     * Method to print the root object.
156     *
157     * @return string
158     */
159    public function __toString(): string
160    {
161        return '%PDF-' . $this->version . "\n" .
162            str_replace(['[{root_index}]', '[{parent_index}]', '[{form_index}]'], [(string)$this->index, (string)$this->parent, ''], $this->data);
163    }
164
165}