Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
73 / 73
100.00% covered (success)
100.00%
7 / 7
CRAP
100.00% covered (success)
100.00%
1 / 1
Wrap
100.00% covered (success)
100.00%
73 / 73
100.00% covered (success)
100.00%
7 / 7
33
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 createLeft
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 createRight
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setBox
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
6
 setBoxCoordinates
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 getBox
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getStrings
100.00% covered (success)
100.00%
53 / 53
100.00% covered (success)
100.00%
1 / 1
21
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\Document\Page\Text;
16
17use Pop\Pdf\Document\Page;
18use Pop\Pdf\Document\Font;
19use InvalidArgumentException;
20
21/**
22 * Pdf page text wrap class
23 *
24 * @category   Pop
25 * @package    Pop\Pdf
26 * @author     Nick Sagona, III <nick@popphp.org>
27 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
28 * @license    https://www.popphp.org/license     New BSD License
29 * @version    6.0.0
30 */
31class Wrap extends AbstractAlignment
32{
33
34   /**
35     * Wrap box boundary
36     * @var array
37     */
38    protected array $box = [
39        'left'   => 0,
40        'right'  => 0,
41        'top'    => 0,
42        'bottom' => 0
43    ];
44
45    /**
46     * Constructor
47     *
48     * Instantiate a PDF text wrap object.
49     *
50     * @param string $alignment
51     * @param int    $leftX
52     * @param int    $rightX
53     * @param array  $box
54     * @param int    $leading
55     */
56    public function __construct(string $alignment = self::LEFT, int $leftX = 0, int $rightX = 0, array $box = [], int $leading = 0)
57    {
58        parent::__construct($alignment, $leftX, $rightX, $leading);
59        if (!empty($box)) {
60            $this->setBox($box);
61        }
62    }
63
64    /**
65     * Create LEFT alignment object
66     *
67     * @param int    $leftX
68     * @param int    $rightX
69     * @param array  $box
70     * @param int    $leading
71     * @return Wrap
72     */
73    public static function createLeft(int $leftX = 0, int $rightX = 0, array $box = [], int $leading = 0): Wrap
74    {
75        return new self(self::LEFT, $leftX, $rightX, $box, $leading);
76    }
77
78    /**
79     * Create RIGHT alignment object
80     *
81     * @param int    $leftX
82     * @param int    $rightX
83     * @param array  $box
84     * @param int    $leading
85     * @return Wrap
86     */
87    public static function createRight(int $leftX = 0, int $rightX = 0, array $box = [], int $leading = 0): Wrap
88    {
89        return new self(self::RIGHT, $leftX, $rightX, $box, $leading);
90    }
91
92    /**
93     * Set the wrap box boundary
94     *
95     * @param  array $box
96     * @throws InvalidArgumentException
97     * @return Wrap
98     */
99    public function setBox(array $box): Wrap
100    {
101        if ((count($box) != 4) || !isset($box['left']) || !isset($box['right']) || !isset($box['top']) || !isset($box['bottom'])) {
102            throw new InvalidArgumentException(
103                "Error: The box array must contain the four coordinates 'left', 'right', 'top' and 'bottom'."
104            );
105        }
106
107        $this->box['left']   = $box['left'];
108        $this->box['right']  = $box['right'];
109        $this->box['top']    = $box['top'];
110        $this->box['bottom'] = $box['bottom'];
111
112        return $this;
113    }
114
115    /**
116     * Set the wrap box boundary by coordinates
117     *
118     * @param  int $left
119     * @param  int $right
120     * @param  int $top
121     * @param  int $bottom
122     * @return Wrap
123     */
124    public function setBoxCoordinates(int $left, int $right, int $top, int $bottom): Wrap
125    {
126        $this->box['left']   = $left;
127        $this->box['right']  = $right;
128        $this->box['top']    = $top;
129        $this->box['bottom'] = $bottom;
130
131        return $this;
132    }
133
134    /**
135     * Get the wrap box boundary
136     *
137     * @return array
138     */
139    public function getBox(): array
140    {
141        return $this->box;
142    }
143
144    /**
145     * Get strings
146     *
147     * @param  Page\Text $text
148     * @param  Font      $font
149     * @param  int       $startY
150     * @return array
151     */
152    public function getStrings(Page\Text $text, Font $font, int $startY): array
153    {
154        $stringAry  = ($text->hasStrings()) ? $text->getStrings() : [$text->getString()];
155        $strings    = [];
156        $append     = false;
157        $size       = $text->getSize();
158        $spaceWidth = $font->getStringWidth(' ', $size);
159
160        foreach ($stringAry as $key => $string) {
161            $stringValue = ($string instanceof Page\Text) ? $string->getString() : $string;
162            if (($append) && !empty($curString)) {
163                $stringValue = $curString . ' ' . $stringValue;
164                $append      = false;
165            }
166            $curString  = '';
167            $curWidth   = 0;
168            $words      = explode(' ', $stringValue);
169            $startX     = $this->leftX;
170
171            if ($this->leading == 0) {
172                $this->leading = $size;
173            }
174
175            foreach ($words as $word) {
176                if ($this->isRight()) {
177                    if (($startY <= $this->box['top']) && ($startY >= $this->box['bottom'])) {
178                        $wrapLength = abs($this->rightX - $this->box['right']);
179                        $x          = $this->box['right'];
180                    } else {
181                        $wrapLength = abs($this->rightX - $this->leftX);
182                        $x          = $startX;
183                    }
184                } else {
185                    $x          = $startX;
186                    $wrapLength = (($startY <= $this->box['top']) && ($startY >= $this->box['bottom'])) ?
187                        abs($this->box['left'] - $this->leftX) : abs($this->rightX - $this->leftX);
188                }
189
190                $newString = ($curString != '') ? $curString . ' ' . $word : $word;
191                $wordWidth = $font->getStringWidth($word, $size);
192                $newWidth  = ($curString != '') ? ($curWidth + $spaceWidth + $wordWidth) : $wordWidth;
193
194                if ($newWidth <= $wrapLength) {
195                    $curString = $newString;
196                    $curWidth  = $newWidth;
197                } else {
198                    $strings[] = [
199                        'string' => $curString,
200                        'x'      => $x,
201                        'y'      => $startY
202                    ];
203                    $curString = $word;
204                    $curWidth  = $wordWidth;
205                    $startY   -= $this->leading;
206                }
207            }
208
209            if (!empty($curString)) {
210                if ($key == (count($stringAry) - 1)) {
211                    if ($this->isRight()) {
212                        $x = (($startY <= $this->box['top']) && ($startY >= $this->box['bottom'])) ?
213                            $this->box['right'] : $startX;
214                    } else {
215                        $x = $startX;
216                    }
217
218                    $strings[] = [
219                        'string' => $curString,
220                        'x'      => $x,
221                        'y'      => $startY
222                    ];
223                } else {
224                    $append = true;
225                }
226            }
227        }
228
229        return $strings;
230    }
231
232}