LineBox::appendInline()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 10
dl 0
loc 13
rs 9.9332
c 0
b 0
f 0
cc 1
nc 1
nop 4
1
<?php
2
3
declare(strict_types=1);
4
/**
5
 * LineBox class.
6
 *
7
 * @package   YetiForcePDF\Layout
8
 *
9
 * @copyright YetiForce Sp. z o.o
10
 * @license   MIT
11
 * @author    Rafal Pospiech <[email protected]>
12
 */
13
14
namespace YetiForcePDF\Layout;
15
16
use YetiForcePDF\Html\Element;
17
use YetiForcePDF\Math;
18
use YetiForcePDF\Style\Style;
19
20
/**
21
 * Class LineBox.
22
 */
23
class LineBox extends Box implements BoxInterface
24
{
25
	/**
26
	 * Append block box element.
27
	 *
28
	 * @param \DOMNode                           $childDomElement
29
	 * @param Element                            $element
30
	 * @param Style                              $style
31
	 * @param \YetiForcePDF\Layout\BlockBox|null $parentBlock
32
	 *
33
	 * @return \YetiForcePDF\Layout\BlockBox
34
	 */
35
	public function appendBlock($childDomElement, $element, $style, $parentBlock)
36
	{
37
		return $parentBlock->appendBlock($childDomElement, $element, $style, $parentBlock);
0 ignored issues
show
Bug introduced by
The method appendBlock() does not exist on YetiForcePDF\Layout\BlockBox. Did you maybe mean appendBlockBox()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

37
		return $parentBlock->/** @scrutinizer ignore-call */ appendBlock($childDomElement, $element, $style, $parentBlock);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug introduced by
The method appendBlock() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

37
		return $parentBlock->/** @scrutinizer ignore-call */ appendBlock($childDomElement, $element, $style, $parentBlock);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
38
	}
39
40
	/**
41
	 * Append table block box element.
42
	 *
43
	 * @param \DOMNode                           $childDomElement
44
	 * @param Element                            $element
45
	 * @param Style                              $style
46
	 * @param \YetiForcePDF\Layout\BlockBox|null $parentBlock
47
	 *
48
	 * @return \YetiForcePDF\Layout\BlockBox
49
	 */
50
	public function appendTableBlock($childDomElement, $element, $style, $parentBlock)
51
	{
52
		return $parentBlock->appendTableBlock($childDomElement, $element, $style, $parentBlock);
0 ignored issues
show
Bug introduced by
The method appendTableBlock() does not exist on YetiForcePDF\Layout\BlockBox. Did you maybe mean appendTableWrapperBox()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

52
		return $parentBlock->/** @scrutinizer ignore-call */ appendTableBlock($childDomElement, $element, $style, $parentBlock);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
53
	}
54
55
	/**
56
	 * Append inline block box element.
57
	 *
58
	 * @param \DOMNode                           $childDomElement
59
	 * @param Element                            $element
60
	 * @param Style                              $style
61
	 * @param \YetiForcePDF\Layout\BlockBox|null $parentBlock
62
	 *
63
	 * @return \YetiForcePDF\Layout\InlineBlockBox
64
	 */
65
	public function appendInlineBlock($childDomElement, $element, $style, $parentBlock)
0 ignored issues
show
Unused Code introduced by
The parameter $parentBlock is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

65
	public function appendInlineBlock($childDomElement, $element, $style, /** @scrutinizer ignore-unused */ $parentBlock)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
66
	{
67
		if ('img' === $childDomElement->tagName) {
68
			$box = (new ImageBox())
69
				->setDocument($this->document)
70
				->setElement($element)
71
				->setParent($this)
72
				->setStyle($style)
73
				->init();
74
		} else {
75
			$box = (new InlineBlockBox())
76
				->setDocument($this->document)
77
				->setElement($element)
78
				->setParent($this)
79
				->setStyle($style)
80
				->init();
81
		}
82
		$this->appendChild($box);
83
		$box->getStyle()->init();
84
		$box->buildTree($box);
85
86
		return $box;
87
	}
88
89
	/**
90
	 * Append barcode box element.
91
	 *
92
	 * @param \DOMNode                           $childDomElement
93
	 * @param Element                            $element
94
	 * @param Style                              $style
95
	 * @param \YetiForcePDF\Layout\BlockBox|null $parentBlock
96
	 *
97
	 * @return \YetiForcePDF\Layout\InlineBlockBox
98
	 */
99
	public function appendBarcode($childDomElement, $element, $style, $parentBlock)
0 ignored issues
show
Unused Code introduced by
The parameter $parentBlock is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

99
	public function appendBarcode($childDomElement, $element, $style, /** @scrutinizer ignore-unused */ $parentBlock)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
100
	{
101
		$box = (new BarcodeBox())
102
			->setDocument($this->document)
103
			->setElement($element)
104
			->setParent($this)
105
			->setStyle($style, false)
106
			->init();
107
		$this->appendChild($box);
108
		if ($childDomElement->hasAttribute('data-barcode') && $childDomElement->getAttribute('data-barcode')) {
0 ignored issues
show
Bug introduced by
The method hasAttribute() does not exist on DOMNode. Did you maybe mean hasAttributes()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

108
		if ($childDomElement->/** @scrutinizer ignore-call */ hasAttribute('data-barcode') && $childDomElement->getAttribute('data-barcode')) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
109
			$box->setType($childDomElement->getAttribute('data-barcode'));
110
		}
111
		if ($childDomElement->hasAttribute('data-size') && $childDomElement->getAttribute('data-size')) {
112
			$box->setSize($childDomElement->getAttribute('data-size'));
113
		}
114
		if ($childDomElement->hasAttribute('data-height') && $childDomElement->getAttribute('data-height')) {
115
			$box->setHeight($childDomElement->getAttribute('data-height'));
116
		}
117
		if ($childDomElement->hasAttribute('data-code') && $childDomElement->getAttribute('data-code')) {
118
			$box->setCode($childDomElement->getAttribute('data-code'));
119
		}
120
		$box->generateBarcodeImage();
121
		$box->getStyle()->init();
122
		$box->buildTree($box);
123
124
		return $box;
125
	}
126
127
	/**
128
	 * Add inline child (and split text to individual characters).
129
	 *
130
	 * @param \DOMNode                           $childDomElement
131
	 * @param Element                            $element
132
	 * @param Style                              $style
133
	 * @param \YetiForcePDF\Layout\BlockBox|null $parentBlock
134
	 *
135
	 * @return \YetiForcePDF\Layout\InlineBox
136
	 */
137
	public function appendInline($childDomElement, $element, $style, $parentBlock)
0 ignored issues
show
Unused Code introduced by
The parameter $childDomElement is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

137
	public function appendInline(/** @scrutinizer ignore-unused */ $childDomElement, $element, $style, $parentBlock)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
138
	{
139
		$box = (new InlineBox())
140
			->setDocument($this->document)
141
			->setElement($element)
142
			->setParent($this)
143
			->setStyle($style)
144
			->init();
145
		$this->appendChild($box);
146
		$box->getStyle()->init();
147
		$box->buildTree($parentBlock);
148
149
		return $box;
150
	}
151
152
	/**
153
	 * Is this line empty?  - filled with whitespaces / non measurable elements.
154
	 */
155
	public function isEmpty()
156
	{
157
		foreach ($this->getChildren() as $child) {
158
			if ($child->isForMeasurement() || $child->getStyle()->haveSpacing()) {
159
				return false;
160
			}
161
		}
162
163
		return true;
164
	}
165
166
	/**
167
	 * Will this box fit in line? (or need to create new one).
168
	 *
169
	 * @param \YetiForcePDF\Layout\Box $box
170
	 *
171
	 * @return bool
172
	 */
173
	public function willFit(Box $box)
174
	{
175
		$childrenWidth = $this->getChildrenWidth();
176
		$availableSpace = $this->getDimensions()->computeAvailableSpace();
177
		$boxWidth = $box->getDimensions()->getWidth();
178
		if (!$boxWidth) {
179
			$boxWidth = $box->getDimensions()->getOuterWidth();
180
		}
181
182
		return Math::comp(Math::sub($availableSpace, $childrenWidth), $boxWidth) >= 0;
183
	}
184
185
	/**
186
	 * Remove white spaces.
187
	 *
188
	 * @return $this
189
	 */
190
	public function removeWhiteSpaces()
191
	{
192
		$this->iterateChildren(function ($child) {
193
			if ($child->containContent()) {
194
				$child->setForMeasurement(true);
195
196
				return false;
197
			}
198
			$child->setForMeasurement(false);
199
		}, true, false);
200
201
		return $this;
202
	}
203
204
	/**
205
	 * Divide this line into more lines when objects doesn't fit.
206
	 *
207
	 * @return LineBox[]
208
	 */
209
	public function divide()
210
	{
211
		$lines = [];
212
		$line = (new self())
213
			->setDocument($this->document)
214
			->setParent($this->getParent())
215
			->setStyle(clone $this->style)
216
			->init();
217
		$children = $this->getChildren();
218
		foreach ($children as $index => $childBox) {
219
			if ($line->willFit($childBox)) {
220
				// if this is beginning of the line
221
				if (!$line->containContent()) {
222
					if (!$childBox->containContent()) {
223
						$childBox->setForMeasurement(false);
224
					} else {
225
						$childBox->setForMeasurement(true);
226
					}
227
					$line->appendChild($childBox);
228
				} else {
229
					if (!$childBox->containContent()) {
230
						// if we doesn't have content and previous element too do not measure me
231
						if ($previous = $children[$index - 1]) {
232
							if (!$previous->containContent()) {
233
								$childBox->setForMeasurement(false);
234
							} else {
235
								$childBox->setForMeasurement(true);
236
							}
237
						} else {
238
							$childBox->setForMeasurement(true);
239
						}
240
					}
241
					$line->appendChild($childBox);
242
				}
243
			} else {
244
				$lines[] = $line;
245
				$line = (new self())
246
					->setDocument($this->document)
247
					->setParent($this->getParent())
248
					->setStyle(clone $this->style)
249
					->init();
250
				if (!$childBox->containContent()) {
251
					$childBox->setForMeasurement(false);
252
				} else {
253
					$childBox->setForMeasurement(true);
254
				}
255
				$line->appendChild($childBox);
256
			}
257
		}
258
		// append last line
259
		$lines[] = $line;
260
		foreach ($lines as $line) {
261
			$isForMeasurement = false;
262
			foreach ($line->getChildren() as $child) {
263
				if ($child->isForMeasurement()) {
264
					$isForMeasurement = true;
265
266
					break;
267
				}
268
			}
269
			$line->forMeasurement = $isForMeasurement;
270
		}
271
		unset($children);
272
273
		return $lines;
274
	}
275
276
	/**
277
	 * Measure width.
278
	 *
279
	 * @param bool $afterPageDividing
280
	 *
281
	 * @return $this
282
	 */
283
	public function measureWidth(bool $afterPageDividing = false)
284
	{
285
		$this->clearStyles();
286
		$width = '0';
287
		foreach ($this->getChildren() as $child) {
288
			$child->measureWidth($afterPageDividing);
0 ignored issues
show
Bug introduced by
The method measureWidth() does not exist on YetiForcePDF\Layout\Box. It seems like you code against a sub-type of said class. However, the method does not exist in YetiForcePDF\Layout\ElementBox. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

288
			$child->/** @scrutinizer ignore-call */ 
289
           measureWidth($afterPageDividing);
Loading history...
289
			$width = Math::add($width, $child->getDimensions()->getOuterWidth());
290
		}
291
		$this->getDimensions()->setWidth($width);
292
		return $this;
293
	}
294
295
	/**
296
	 * Measure height.
297
	 *
298
	 * @param bool $afterPageDividing
299
	 *
300
	 * @return $this
301
	 */
302
	public function measureHeight(bool $afterPageDividing = false)
303
	{
304
		if (!$this->isForMeasurement() || $this->isEmpty()) {
305
			$this->getDimensions()->setHeight('0');
306
			return $this;
307
		}
308
		foreach ($this->getChildren() as $child) {
309
			$child->measureHeight($afterPageDividing);
0 ignored issues
show
Bug introduced by
The method measureHeight() does not exist on YetiForcePDF\Layout\Box. It seems like you code against a sub-type of said class. However, the method does not exist in YetiForcePDF\Layout\ElementBox. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

309
			$child->/** @scrutinizer ignore-call */ 
310
           measureHeight($afterPageDividing);
Loading history...
310
		}
311
		$lineHeight = $this->getStyle()->getMaxLineHeight();
312
		$this->getDimensions()->setHeight($lineHeight);
313
		$this->measureMargins();
314
315
		return $this;
316
	}
317
318
	/**
319
	 * Measure margins.
320
	 *
321
	 * @return $this
322
	 */
323
	public function measureMargins()
324
	{
325
		$allChildren = [];
326
		$this->getAllChildren($allChildren, false);
327
		$marginTop = '0';
328
		$marginBottom = '0';
329
		foreach ($allChildren as $child) {
330
			if ($child instanceof InlineBlockBox) {
331
				$marginTop = Math::max($marginTop, $child->getStyle()->getRules('margin-top'));
0 ignored issues
show
Bug introduced by
It seems like $child->getStyle()->getRules('margin-top') can also be of type array; however, parameter $numbers of YetiForcePDF\Math::max() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

331
				$marginTop = Math::max($marginTop, /** @scrutinizer ignore-type */ $child->getStyle()->getRules('margin-top'));
Loading history...
332
				$marginBottom = Math::max($marginBottom, $child->getStyle()->getRules('margin-bottom'));
333
			}
334
		}
335
		$style = $this->getStyle();
336
		$style->setRule('margin-top', $marginTop);
337
		$style->setRule('margin-bottom', $marginBottom);
338
339
		return $this;
340
	}
341
342
	/**
343
	 * Position.
344
	 *
345
	 * @param bool $afterPageDividing
346
	 *
347
	 * @return $this
348
	 */
349
	public function measureOffset(bool $afterPageDividing = false)
350
	{
351
		$parent = $this->getParent();
352
		$parentStyle = $parent->getStyle();
353
		$top = $parentStyle->getOffsetTop();
354
		$left = $parentStyle->getOffsetLeft();
355
		$previous = $this->getPrevious();
356
		if ($previous && !$previous->isAbsolute()) {
357
			$top = Math::add($previous->getOffset()->getTop(), $previous->getDimensions()->getHeight(), $previous->getStyle()->getRules('margin-bottom'));
0 ignored issues
show
Bug introduced by
It seems like $previous->getStyle()->getRules('margin-bottom') can also be of type array; however, parameter $numbers of YetiForcePDF\Math::add() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

357
			$top = Math::add($previous->getOffset()->getTop(), $previous->getDimensions()->getHeight(), /** @scrutinizer ignore-type */ $previous->getStyle()->getRules('margin-bottom'));
Loading history...
Bug introduced by
It seems like $previous->getDimensions()->getHeight() can also be of type null; however, parameter $numbers of YetiForcePDF\Math::add() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

357
			$top = Math::add($previous->getOffset()->getTop(), /** @scrutinizer ignore-type */ $previous->getDimensions()->getHeight(), $previous->getStyle()->getRules('margin-bottom'));
Loading history...
358
		}
359
		$top = Math::add($top, $this->getStyle()->getRules('margin-top'));
360
		$this->getOffset()->setTop($top);
361
		$this->getOffset()->setLeft($left);
362
		foreach ($this->getChildren() as $child) {
363
			$child->measureOffset($afterPageDividing);
0 ignored issues
show
Bug introduced by
The method measureOffset() does not exist on YetiForcePDF\Layout\Box. It seems like you code against a sub-type of said class. However, the method does not exist in YetiForcePDF\Layout\ElementBox. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

363
			$child->/** @scrutinizer ignore-call */ 
364
           measureOffset($afterPageDividing);
Loading history...
364
		}
365
366
		return $this;
367
	}
368
369
	/**
370
	 * Position.
371
	 *
372
	 * @param bool $afterPageDividing
373
	 *
374
	 * @return $this
375
	 */
376
	public function measurePosition(bool $afterPageDividing = false)
377
	{
378
		if (!$this->isRenderable()) {
379
			return $this;
380
		}
381
		$parent = $this->getParent();
382
		$this->getCoordinates()->setX(Math::add($parent->getCoordinates()->getX(), $this->getOffset()->getLeft()));
383
		$this->getCoordinates()->setY(Math::add($parent->getCoordinates()->getY(), $this->getOffset()->getTop()));
384
		foreach ($this->getChildren() as $child) {
385
			$child->measurePosition($afterPageDividing);
0 ignored issues
show
Bug introduced by
The method measurePosition() does not exist on YetiForcePDF\Layout\Box. It seems like you code against a sub-type of said class. However, the method does not exist in YetiForcePDF\Layout\ElementBox. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

385
			$child->/** @scrutinizer ignore-call */ 
386
           measurePosition($afterPageDividing);
Loading history...
386
		}
387
388
		return $this;
389
	}
390
391
	/**
392
	 * Clear styles
393
	 * return $this;.
394
	 */
395
	public function clearStyles()
396
	{
397
		$allNestedChildren = [];
398
		$maxLevel = '0';
399
		foreach ($this->getChildren() as $child) {
400
			$allChildren = [];
401
			$child->getAllChildren($allChildren);
402
			$maxLevel = Math::max($maxLevel, (string) \count($allChildren));
403
			$allNestedChildren[] = $allChildren;
404
		}
405
		$clones = [];
406
		for ($row = 0; $row < $maxLevel; ++$row) {
407
			foreach ($allNestedChildren as $childArray) {
408
				if (isset($childArray[$row])) {
409
					$current = $childArray[$row];
410
					$clones[$current->getId()][] = $current;
411
				}
412
			}
413
		}
414
		foreach ($clones as $row => $cloneArray) {
415
			$count = \count($cloneArray);
416
			if ($count > 1) {
417
				foreach ($cloneArray as $index => $clone) {
418
					if (0 === $index) {
419
						$clone->getStyle()->clearFirstInline();
420
					} elseif ($index === $count - 1) {
421
						$clone->getStyle()->clearLastInline();
422
					} elseif ($index > 0 && $index < ($count - 1)) {
423
						$clone->getStyle()->clearMiddleInline();
424
					}
425
				}
426
			}
427
		}
428
429
		return $this;
430
	}
431
432
	/**
433
	 * Get children width.
434
	 *
435
	 * @return string
436
	 */
437
	public function getChildrenWidth()
438
	{
439
		$width = '0';
440
		foreach ($this->getChildren() as $childBox) {
441
			if ($childBox->isForMeasurement()) {
442
				if ($childWidth = $childBox->getDimensions()->getWidth()) {
443
					$width = Math::add($width, $childWidth);
444
				} else {
445
					$width = Math::add($width, $childBox->getDimensions()->getOuterWidth());
446
				}
447
			}
448
		}
449
450
		return $width;
451
	}
452
453
	/**
454
	 * Get element PDF instructions to use in content stream.
455
	 *
456
	 * @return string
457
	 */
458
	public function getInstructions(): string
459
	{
460
		$coordinates = $this->getCoordinates();
461
		$pdfX = $coordinates->getPdfX();
462
		$pdfY = $coordinates->getPdfY();
463
		$dimensions = $this->getDimensions();
464
		$width = $dimensions->getWidth();
465
		$height = $dimensions->getHeight();
466
		$element = [];
467
		$element = $this->addBorderInstructions($element, $pdfX, $pdfY, $width, $height);
0 ignored issues
show
Bug introduced by
It seems like $height can also be of type null; however, parameter $height of YetiForcePDF\Layout\Box::addBorderInstructions() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

467
		$element = $this->addBorderInstructions($element, $pdfX, $pdfY, $width, /** @scrutinizer ignore-type */ $height);
Loading history...
468
469
		return implode("\n", $element);
470
	}
471
}
472