Completed
Push — master ( a11a2f...a1ae8b )
by Asmir
03:55
created

XmlSerializationVisitor   D

Complexity

Total Complexity 117

Size/Duplication

Total Lines 493
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 90.94%

Importance

Changes 0
Metric Value
wmc 117
lcom 1
cbo 9
dl 0
loc 493
ccs 241
cts 265
cp 0.9094
rs 4.8717
c 0
b 0
f 0

41 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A setDefaultRootName() 0 5 1
A hasDefaultRootName() 0 4 1
A setDefaultVersion() 0 4 1
A setDefaultEncoding() 0 4 1
A setNavigator() 0 7 1
A getNavigator() 0 4 1
A visitNull() 0 19 2
B visitString() 0 18 5
A visitSimpleString() 0 11 2
A visitBoolean() 0 11 4
A visitInteger() 0 4 1
A visitDouble() 0 4 1
F visitArray() 0 33 16
B startVisitingObject() 0 27 5
D visitProperty() 0 94 26
A isInLineCollection() 0 4 2
A isCircularRef() 0 4 1
A isSkippableEmptyObject() 0 4 3
A isSkippableCollection() 0 4 2
A isElementEmpty() 0 4 2
A endVisitingObject() 0 4 1
A getResult() 0 4 1
A getCurrentNode() 0 4 1
A getCurrentMetadata() 0 4 1
A getDocument() 0 4 1
A setCurrentMetadata() 0 5 1
A setCurrentNode() 0 5 1
A revertCurrentNode() 0 4 1
A revertCurrentMetadata() 0 4 1
B createDocument() 0 17 5
A prepare() 0 6 1
A visitNumeric() 0 11 2
A isElementNameValid() 0 4 3
A attachNullNamespace() 0 11 2
A addNamespaceAttributes() 0 12 4
B createElement() 0 13 5
A setAttributeOnNode() 0 11 3
A getClassDefaultNamespace() 0 4 2
A isFormatOutput() 0 4 1
A setFormatOutput() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like XmlSerializationVisitor often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use XmlSerializationVisitor, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * Copyright 2016 Johannes M. Schmitt <[email protected]>
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
namespace JMS\Serializer;
20
21
use JMS\Serializer\Accessor\AccessorStrategyInterface;
22
use JMS\Serializer\Exception\RuntimeException;
23
use JMS\Serializer\Metadata\ClassMetadata;
24
use JMS\Serializer\Metadata\PropertyMetadata;
25
use JMS\Serializer\Naming\PropertyNamingStrategyInterface;
26
27
/**
28
 * XmlSerializationVisitor.
29
 *
30
 * @author Johannes M. Schmitt <[email protected]>
31
 */
32
class XmlSerializationVisitor extends AbstractVisitor
33
{
34
    public $document;
35
36
    private $navigator;
37
    private $defaultRootName = 'result';
38
    private $defaultRootNamespace;
39
    private $defaultVersion = '1.0';
40
    private $defaultEncoding = 'UTF-8';
41
    private $stack;
42
    private $metadataStack;
43
    private $currentNode;
44
    private $currentMetadata;
45
    private $hasValue;
46
    private $nullWasVisited;
47
    private $objectMetadataStack;
48
49
    /** @var boolean */
50
    private $formatOutput;
51
52 379
    public function __construct(PropertyNamingStrategyInterface $namingStrategy, AccessorStrategyInterface $accessorStrategy = null)
53
    {
54 379
        parent::__construct($namingStrategy, $accessorStrategy);
55 379
        $this->objectMetadataStack = new \SplStack;
56 379
        $this->formatOutput = true;
57 379
    }
58
59
    public function setDefaultRootName($name, $namespace = null)
60
    {
61
        $this->defaultRootName = $name;
62
        $this->defaultRootNamespace = $namespace;
63
    }
64
65
    /**
66
     * @return boolean
67
     */
68
    public function hasDefaultRootName()
69
    {
70
        return 'result' === $this->defaultRootName;
71
    }
72
73
    public function setDefaultVersion($version)
74
    {
75
        $this->defaultVersion = $version;
76
    }
77
78
    public function setDefaultEncoding($encoding)
79
    {
80
        $this->defaultEncoding = $encoding;
81
    }
82
83 107
    public function setNavigator(GraphNavigator $navigator)
84
    {
85 107
        $this->navigator = $navigator;
86 107
        $this->document = null;
87 107
        $this->stack = new \SplStack;
88 107
        $this->metadataStack = new \SplStack;
89 107
    }
90
91
    public function getNavigator()
92
    {
93
        return $this->navigator;
94
    }
95
96 9
    public function visitNull($data, array $type, Context $context)
97
    {
98 9
        if (null === $this->document) {
99 6
            $this->document = $this->createDocument(null, null, true);
100 6
            $node = $this->document->createAttribute('xsi:nil');
101 6
            $node->value = 'true';
102 6
            $this->currentNode->appendChild($node);
103
104 6
            $this->attachNullNamespace();
105
106 6
            return;
107
        }
108
109 3
        $node = $this->document->createAttribute('xsi:nil');
0 ignored issues
show
Bug introduced by
The method createAttribute cannot be called on $this->document (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
110 3
        $node->value = 'true';
111 3
        $this->attachNullNamespace();
112
113 3
        return $node;
114
    }
115
116 73
    public function visitString($data, array $type, Context $context)
117
    {
118
119 73
        if (null !== $this->currentMetadata) {
120 65
            $doCData = $this->currentMetadata->xmlElementCData;
121 65
        } else {
122 9
            $doCData = true;
123
        }
124
125 73
        if (null === $this->document) {
126 5
            $this->document = $this->createDocument(null, null, true);
127 5
            $this->currentNode->appendChild($doCData ? $this->document->createCDATASection($data) : $this->document->createTextNode((string)$data));
128
129 5
            return;
130
        }
131
132 68
        return $doCData ? $this->document->createCDATASection($data) : $this->document->createTextNode((string)$data);
0 ignored issues
show
Bug introduced by
The method createCDATASection cannot be called on $this->document (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
133
    }
134
135 2
    public function visitSimpleString($data, array $type, Context $context)
0 ignored issues
show
Unused Code introduced by
The parameter $type is not used and could be removed.

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

Loading history...
Unused Code introduced by
The parameter $context is not used and could be removed.

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

Loading history...
136
    {
137 2
        if (null === $this->document) {
138 2
            $this->document = $this->createDocument(null, null, true);
139 2
            $this->currentNode->appendChild($this->document->createTextNode((string)$data));
140
141 2
            return;
142
        }
143
144
        return $this->document->createTextNode((string)$data);
145
    }
146
147 5
    public function visitBoolean($data, array $type, Context $context)
148
    {
149 5
        if (null === $this->document) {
150 2
            $this->document = $this->createDocument(null, null, true);
151 2
            $this->currentNode->appendChild($this->document->createTextNode($data ? 'true' : 'false'));
152
153 2
            return;
154
        }
155
156 3
        return $this->document->createTextNode($data ? 'true' : 'false');
157
    }
158
159 19
    public function visitInteger($data, array $type, Context $context)
160
    {
161 19
        return $this->visitNumeric($data, $type);
162
    }
163
164 9
    public function visitDouble($data, array $type, Context $context)
165
    {
166 9
        return $this->visitNumeric($data, $type);
167
    }
168
169 28
    public function visitArray($data, array $type, Context $context)
170
    {
171 28
        if (null === $this->document) {
172 9
            $this->document = $this->createDocument(null, null, true);
173 9
        }
174
175 28
        $entryName = (null !== $this->currentMetadata && null !== $this->currentMetadata->xmlEntryName) ? $this->currentMetadata->xmlEntryName : 'entry';
176 28
        $keyAttributeName = (null !== $this->currentMetadata && null !== $this->currentMetadata->xmlKeyAttribute) ? $this->currentMetadata->xmlKeyAttribute : null;
177 28
        $namespace = (null !== $this->currentMetadata && null !== $this->currentMetadata->xmlEntryNamespace) ? $this->currentMetadata->xmlEntryNamespace : null;
178
179 28
        foreach ($data as $k => $v) {
180
181 27
            if (null === $v && $context->shouldSerializeNull() !== true) {
182 1
                continue;
183
            }
184
185 27
            $tagName = (null !== $this->currentMetadata && $this->currentMetadata->xmlKeyValuePairs && $this->isElementNameValid($k)) ? $k : $entryName;
186
187 27
            $entryNode = $this->createElement($tagName, $namespace);
188 27
            $this->currentNode->appendChild($entryNode);
189 27
            $this->setCurrentNode($entryNode);
190
191 27
            if (null !== $keyAttributeName) {
192 7
                $entryNode->setAttribute($keyAttributeName, (string)$k);
193 7
            }
194
195 27
            if (null !== $node = $this->navigator->accept($v, $this->getElementType($type), $context)) {
196 18
                $this->currentNode->appendChild($node);
197 18
            }
198
199 27
            $this->revertCurrentNode();
200 28
        }
201 28
    }
202
203 73
    public function startVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context)
204
    {
205 73
        $this->objectMetadataStack->push($metadata);
206
207 73
        if (null === $this->document) {
208 71
            $this->document = $this->createDocument(null, null, false);
209 71
            if ($metadata->xmlRootName) {
210 19
                $rootName = $metadata->xmlRootName;
211 19
                $rootNamespace = $metadata->xmlRootNamespace ?: $this->getClassDefaultNamespace($metadata);
212 19
            } else {
213 52
                $rootName = $this->defaultRootName;
214 52
                $rootNamespace = $this->defaultRootNamespace;
215
            }
216
217 71
            if ($rootNamespace) {
218 7
                $this->currentNode = $this->document->createElementNS($rootNamespace, $rootName);
219 7
            } else {
220 64
                $this->currentNode = $this->document->createElement($rootName);
221
            }
222
223 71
            $this->document->appendChild($this->currentNode);
224 71
        }
225
226 73
        $this->addNamespaceAttributes($metadata, $this->currentNode);
227
228 73
        $this->hasValue = false;
229 73
    }
230
231 73
    public function visitProperty(PropertyMetadata $metadata, $object, Context $context)
232
    {
233 73
        $v = $this->accessor->getValue($object, $metadata);
234
235 72
        if (null === $v && $context->shouldSerializeNull() !== true) {
236 8
            return;
237
        }
238
239 72
        if ($metadata->xmlAttribute) {
240 12
            $this->setCurrentMetadata($metadata);
241 12
            $node = $this->navigator->accept($v, $metadata->type, $context);
242 12
            $this->revertCurrentMetadata();
243
244 12
            if (!$node instanceof \DOMCharacterData) {
245
                throw new RuntimeException(sprintf('Unsupported value for XML attribute for %s. Expected character data, but got %s.', $metadata->name, json_encode($v)));
246
            }
247 12
            $attributeName = $this->namingStrategy->translateName($metadata);
248 12
            $this->setAttributeOnNode($this->currentNode, $attributeName, $node->nodeValue, $metadata->xmlNamespace);
249
250 12
            return;
251
        }
252
253 70
        if (($metadata->xmlValue && $this->currentNode->childNodes->length > 0)
254 70
            || (!$metadata->xmlValue && $this->hasValue)
255 70
        ) {
256 1
            throw new RuntimeException(sprintf('If you make use of @XmlValue, all other properties in the class must have the @XmlAttribute annotation. Invalid usage detected in class %s.', $metadata->class));
257
        }
258
259 70
        if ($metadata->xmlValue) {
260 8
            $this->hasValue = true;
261
262 8
            $this->setCurrentMetadata($metadata);
263 8
            $node = $this->navigator->accept($v, $metadata->type, $context);
264 8
            $this->revertCurrentMetadata();
265
266 8
            if (!$node instanceof \DOMCharacterData) {
267
                throw new RuntimeException(sprintf('Unsupported value for property %s::$%s. Expected character data, but got %s.', $metadata->reflection->class, $metadata->reflection->name, is_object($node) ? get_class($node) : gettype($node)));
268
            }
269
270 8
            $this->currentNode->appendChild($node);
271
272 8
            return;
273
        }
274
275 66
        if ($metadata->xmlAttributeMap) {
276 2
            if (!is_array($v)) {
277 1
                throw new RuntimeException(sprintf('Unsupported value type for XML attribute map. Expected array but got %s.', gettype($v)));
278
            }
279
280 1
            foreach ($v as $key => $value) {
281 1
                $this->setCurrentMetadata($metadata);
282 1
                $node = $this->navigator->accept($value, null, $context);
283 1
                $this->revertCurrentMetadata();
284
285 1
                if (!$node instanceof \DOMCharacterData) {
286
                    throw new RuntimeException(sprintf('Unsupported value for a XML attribute map value. Expected character data, but got %s.', json_encode($v)));
287
                }
288
289 1
                $this->setAttributeOnNode($this->currentNode, $key, $node->nodeValue, $metadata->xmlNamespace);
290 1
            }
291
292 1
            return;
293
        }
294
295 64
        if ($addEnclosingElement = !$this->isInLineCollection($metadata) && !$metadata->inline) {
0 ignored issues
show
Comprehensibility introduced by
Consider adding parentheses for clarity. Current Interpretation: $addEnclosingElement = (... && !$metadata->inline), Probably Intended Meaning: ($addEnclosingElement = ...) && !$metadata->inline
Loading history...
296 63
            $elementName = $this->namingStrategy->translateName($metadata);
297
298 63
            $namespace = null !== $metadata->xmlNamespace
299 63
                ? $metadata->xmlNamespace
300 63
                : $this->getClassDefaultNamespace($this->objectMetadataStack->top());
301
302 63
            $element = $this->createElement($elementName, $namespace);
303 63
            $this->currentNode->appendChild($element);
304 63
            $this->setCurrentNode($element);
305 63
        }
306
307 64
        $this->setCurrentMetadata($metadata);
308
309 64
        if (null !== $node = $this->navigator->accept($v, $metadata->type, $context)) {
310 53
            $this->currentNode->appendChild($node);
311 53
        }
312
313 64
        $this->revertCurrentMetadata();
314
315 64
        if ($addEnclosingElement) {
316 63
            $this->revertCurrentNode();
317
318 63
            if ($this->isElementEmpty($element) && ($v === null || $this->isSkippableCollection($metadata) || $this->isSkippableEmptyObject($node, $metadata) || $this->isCircularRef($context, $v))) {
0 ignored issues
show
Compatibility introduced by
$context of type object<JMS\Serializer\Context> is not a sub-type of object<JMS\Serializer\SerializationContext>. It seems like you assume a child class of the class JMS\Serializer\Context to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
319 5
                $this->currentNode->removeChild($element);
0 ignored issues
show
Bug introduced by
The variable $element does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
320 5
            }
321 63
        }
322
323 64
        $this->hasValue = false;
324 64
    }
325
326 64
    private function isInLineCollection(PropertyMetadata $metadata)
327
    {
328 64
        return $metadata->xmlCollection && $metadata->xmlCollectionInline;
329
    }
330
331 4
    private function isCircularRef(SerializationContext $context, $v)
332
    {
333 4
        return $context->isVisiting($v);
334
    }
335
336 6
    private function isSkippableEmptyObject($node, PropertyMetadata $metadata)
337
    {
338 6
        return $node === null && !$metadata->xmlCollection && $metadata->skipWhenEmpty;
339
    }
340
341 7
    private function isSkippableCollection(PropertyMetadata $metadata)
342
    {
343 7
        return $metadata->xmlCollection && $metadata->xmlCollectionSkipWhenEmpty;
344
    }
345
346 63
    private function isElementEmpty(\DOMElement $element)
347
    {
348 63
        return !$element->hasChildNodes() && !$element->hasAttributes();
349
    }
350
351 70
    public function endVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context)
352
    {
353 70
        $this->objectMetadataStack->pop();
354 70
    }
355
356 102
    public function getResult()
357
    {
358 102
        return $this->document->saveXML();
359
    }
360
361 2
    public function getCurrentNode()
362
    {
363 2
        return $this->currentNode;
364
    }
365
366
    public function getCurrentMetadata()
367
    {
368
        return $this->currentMetadata;
369
    }
370
371
    public function getDocument()
372
    {
373
        return $this->document;
374
    }
375
376 71
    public function setCurrentMetadata(PropertyMetadata $metadata)
377
    {
378 71
        $this->metadataStack->push($this->currentMetadata);
379 71
        $this->currentMetadata = $metadata;
380 71
    }
381
382 95
    public function setCurrentNode(\DOMNode $node)
383
    {
384 95
        $this->stack->push($this->currentNode);
385 95
        $this->currentNode = $node;
386 95
    }
387
388 71
    public function revertCurrentNode()
389
    {
390 71
        return $this->currentNode = $this->stack->pop();
391
    }
392
393 71
    public function revertCurrentMetadata()
394
    {
395 71
        return $this->currentMetadata = $this->metadataStack->pop();
396
    }
397
398 105
    public function createDocument($version = null, $encoding = null, $addRoot = true)
399
    {
400 105
        $doc = new \DOMDocument($version ?: $this->defaultVersion, $encoding ?: $this->defaultEncoding);
401 105
        $doc->formatOutput = $this->isFormatOutput();
402
403 105
        if ($addRoot) {
404 30
            if ($this->defaultRootNamespace) {
405
                $rootNode = $doc->createElementNS($this->defaultRootNamespace, $this->defaultRootName);
406
            } else {
407 30
                $rootNode = $doc->createElement($this->defaultRootName);
408
            }
409 30
            $this->setCurrentNode($rootNode);
410 30
            $doc->appendChild($rootNode);
411 30
        }
412
413 105
        return $doc;
414
    }
415
416 107
    public function prepare($data)
417
    {
418 107
        $this->nullWasVisited = false;
419
420 107
        return $data;
421
    }
422
423 28
    private function visitNumeric($data, array $type)
0 ignored issues
show
Unused Code introduced by
The parameter $type is not used and could be removed.

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

Loading history...
424
    {
425 28
        if (null === $this->document) {
426 5
            $this->document = $this->createDocument(null, null, true);
427 5
            $this->currentNode->appendChild($textNode = $this->document->createTextNode((string)$data));
428
429 5
            return $textNode;
430
        }
431
432 23
        return $this->document->createTextNode((string)$data);
433
    }
434
435
    /**
436
     * Checks that the name is a valid XML element name.
437
     *
438
     * @param string $name
439
     *
440
     * @return boolean
441
     */
442 2
    private function isElementNameValid($name)
443
    {
444 2
        return $name && false === strpos($name, ' ') && preg_match('#^[\pL_][\pL0-9._-]*$#ui', $name);
445
    }
446
447 9
    private function attachNullNamespace()
448
    {
449 9
        if (!$this->nullWasVisited) {
450 9
            $this->document->documentElement->setAttributeNS(
451 9
                'http://www.w3.org/2000/xmlns/',
452 9
                'xmlns:xsi',
453
                'http://www.w3.org/2001/XMLSchema-instance'
454 9
            );
455 9
            $this->nullWasVisited = true;
456 9
        }
457 9
    }
458
459
    /**
460
     * Adds namespace attributes to the XML root element
461
     *
462
     * @param \JMS\Serializer\Metadata\ClassMetadata $metadata
463
     * @param \DOMElement $element
464
     */
465 73
    private function addNamespaceAttributes(ClassMetadata $metadata, \DOMElement $element)
466
    {
467 73
        foreach ($metadata->xmlNamespaces as $prefix => $uri) {
468 9
            $attribute = 'xmlns';
469 9
            if ($prefix !== '') {
470 9
                $attribute .= ':' . $prefix;
471 9
            } elseif ($element->namespaceURI === $uri) {
472 4
                continue;
473
            }
474 9
            $element->setAttributeNS('http://www.w3.org/2000/xmlns/', $attribute, $uri);
475 73
        }
476 73
    }
477
478 71
    private function createElement($tagName, $namespace = null)
479
    {
480 71
        if (null === $namespace) {
481 65
            return $this->document->createElement($tagName);
482
        }
483 9
        if ($this->currentNode->isDefaultNamespace($namespace)) {
484 5
            return $this->document->createElementNS($namespace, $tagName);
485
        }
486 9
        if (!($prefix = $this->currentNode->lookupPrefix($namespace)) && !($prefix = $this->document->lookupPrefix($namespace))) {
487 3
            $prefix = 'ns-' . substr(sha1($namespace), 0, 8);
488 3
        }
489 9
        return $this->document->createElementNS($namespace, $prefix . ':' . $tagName);
490
    }
491
492 13
    private function setAttributeOnNode(\DOMElement $node, $name, $value, $namespace = null)
493
    {
494 13
        if (null !== $namespace) {
495 4
            if (!$prefix = $node->lookupPrefix($namespace)) {
496 2
                $prefix = 'ns-' . substr(sha1($namespace), 0, 8);
497 2
            }
498 4
            $node->setAttributeNS($namespace, $prefix . ':' . $name, $value);
499 4
        } else {
500 11
            $node->setAttribute($name, $value);
501
        }
502 13
    }
503
504 62
    private function getClassDefaultNamespace(ClassMetadata $metadata)
505
    {
506 62
        return (isset($metadata->xmlNamespaces['']) ? $metadata->xmlNamespaces[''] : null);
507
    }
508
509
    /**
510
     * @return bool
511
     */
512 105
    public function isFormatOutput()
513
    {
514 105
        return $this->formatOutput;
515
    }
516
517
    /**
518
     * @param bool $formatOutput
519
     */
520 1
    public function setFormatOutput($formatOutput)
521
    {
522 1
        $this->formatOutput = (boolean)$formatOutput;
523 1
    }
524
}
525