Passed
Push — master ( dba7cd...d89126 )
by Asmir
01:36
created

HeaderHandler::deserializeHeaderPlaceholder()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 10
nc 3
nop 4
dl 0
loc 17
rs 9.9332
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace GoetasWebservices\SoapServices\Metadata\Headers\Handler;
6
7
use GoetasWebservices\SoapServices\Metadata\Envelope\Envelope;
8
use GoetasWebservices\SoapServices\Metadata\Headers\Header;
9
use GoetasWebservices\SoapServices\Metadata\Headers\HeadersIncoming;
10
use GoetasWebservices\SoapServices\Metadata\Headers\HeadersOutgoing;
11
use JMS\Serializer\DeserializationContext;
12
use JMS\Serializer\EventDispatcher\EventSubscriberInterface;
13
use JMS\Serializer\EventDispatcher\PreSerializeEvent;
14
use JMS\Serializer\GraphNavigator;
15
use JMS\Serializer\Handler\SubscribingHandlerInterface;
16
use JMS\Serializer\Metadata\StaticPropertyMetadata;
17
use JMS\Serializer\SerializationContext;
18
use JMS\Serializer\XmlDeserializationVisitor;
19
use JMS\Serializer\XmlSerializationVisitor;
20
21
class HeaderHandler implements SubscribingHandlerInterface, EventSubscriberInterface
22
{
23
    /**
24
     * {@inheritdoc}
25
     */
26
    public static function getSubscribedEvents()
27
    {
28
        return [
29
            ['event' => 'serializer.pre_serialize', 'method' => 'ensureHeaderSerialized', 'interface' => Envelope::class],
30
        ];
31
    }
32
33
    public static function getSubscribingMethods(): array
34
    {
35
        return [
36
            [
37
                'direction' => GraphNavigator::DIRECTION_DESERIALIZATION,
38
                'format' => 'xml',
39
                'type' => 'GoetasWebservices\SoapServices\Metadata\Headers\RawFaultDetail',
40
                'method' => 'deserializeFaultDetail',
41
            ],
42
            [
43
                'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
44
                'format' => 'xml',
45
                'type' => 'GoetasWebservices\SoapServices\Metadata\Headers\Handler\HeaderPlaceholder',
46
                'method' => 'serializeHeaderPlaceholder',
47
            ],
48
            [
49
                'direction' => GraphNavigator::DIRECTION_DESERIALIZATION,
50
                'format' => 'xml',
51
                'type' => 'GoetasWebservices\SoapServices\Metadata\Headers\Handler\HeaderPlaceholder',
52
                'method' => 'deserializeHeaderPlaceholder',
53
            ],
54
            [
55
                'direction' => GraphNavigator::DIRECTION_DESERIALIZATION,
56
                'format' => 'xml',
57
                'type' => 'GoetasWebservices\SoapServices\SoapEnvelope\Header',
58
                'method' => 'deserializeHeader',
59
            ],
60
            [
61
                'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
62
                'format' => 'xml',
63
                'type' => Header::class,
64
                'method' => 'serializeHeader',
65
            ],
66
        ];
67
    }
68
69
    public function ensureHeaderSerialized(PreSerializeEvent $event): void
70
    {
71
        $envelope = $event->getObject();
72
        if (!($envelope instanceof Envelope)) {
73
            return;
74
        }
75
76
        $context = $event->getContext();
77
        $headerBag = $context->getAttribute('headers_outgoing');
78
        \assert($headerBag instanceof HeadersOutgoing);
79
80
        if (count($headerBag->getHeaders()) > 0 && !$envelope->getHeader()) {
0 ignored issues
show
Bug introduced by
The method getHeader() does not exist on GoetasWebservices\SoapSe...adata\Envelope\Envelope. ( Ignorable by Annotation )

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

80
        if (count($headerBag->getHeaders()) > 0 && !$envelope->/** @scrutinizer ignore-call */ getHeader()) {

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...
81
            $factory = $event->getContext()->getMetadataFactory();
82
            $envelopeMetadata = $factory->getMetadataForClass($event->getType()['name']);
83
            $headerType = $envelopeMetadata->propertyMetadata['header']->type;
0 ignored issues
show
Bug introduced by
The property propertyMetadata does not seem to exist on Metadata\ClassHierarchyMetadata.
Loading history...
84
            $defaultHeaderClass = $headerType['params'][0];
85
            $envelope->setHeader(new $defaultHeaderClass());
0 ignored issues
show
Bug introduced by
The method setHeader() does not exist on GoetasWebservices\SoapSe...adata\Envelope\Envelope. ( Ignorable by Annotation )

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

85
            $envelope->/** @scrutinizer ignore-call */ 
86
                       setHeader(new $defaultHeaderClass());

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...
86
        }
87
    }
88
89
    /**
90
     * @return mixed
91
     */
92
    public function deserializeHeaderPlaceholder(XmlDeserializationVisitor $visitor, \SimpleXMLElement $data, array $type, DeserializationContext $context)
93
    {
94
        $type = ['name' => $type['params'][0], 'params' => []];
95
        $headers = $context->getNavigator()->accept($data, $type, $context);
0 ignored issues
show
Unused Code introduced by
The call to JMS\Serializer\GraphNavigatorInterface::accept() has too many arguments starting with $context. ( Ignorable by Annotation )

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

95
        $headers = $context->getNavigator()->/** @scrutinizer ignore-call */ accept($data, $type, $context);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
96
97
        $headerBag = $context->getAttribute('headers_incoming');
98
        \assert($headerBag instanceof HeadersIncoming);
99
100
        foreach ($data->xpath('./*') as $node) {
101
            if ($this->isMustUnderstand($node, $visitor, $context)) {
102
                $headerBag->addMustUnderstandHeader($node);
103
            } else {
104
                $headerBag->addHeader($node);
105
            }
106
        }
107
108
        return $headers;
109
    }
110
111
    /**
112
     * @return mixed
113
     */
114
    public function deserializeHeader(XmlDeserializationVisitor $visitor, \SimpleXMLElement $data, array $type, DeserializationContext $context)
115
    {
116
        $type = ['name' => $type['params'][0], 'params' => []];
117
118
        $return = $context->getNavigator()->accept($data, $type, $context);
0 ignored issues
show
Unused Code introduced by
The call to JMS\Serializer\GraphNavigatorInterface::accept() has too many arguments starting with $context. ( Ignorable by Annotation )

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

118
        $return = $context->getNavigator()->/** @scrutinizer ignore-call */ accept($data, $type, $context);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
119
120
        $headerBag = $context->getAttribute('headers_incoming');
121
        \assert($headerBag instanceof HeadersIncoming);
122
123
        if ($this->isMustUnderstand($data, $visitor, $context)) {
124
            $headerBag->addMustUnderstandHeader($data, $return);
125
        } else {
126
            $headerBag->addHeader($data, $return);
127
        }
128
129
        return $return;
130
    }
131
132
    private function isMustUnderstand(\SimpleXMLElement $data, XmlDeserializationVisitor $visitor, DeserializationContext $context): bool
133
    {
134
        $domElement = dom_import_simplexml($data);
135
        $mustUnderstandAttr = $domElement->getAttributeNS($domElement->ownerDocument->documentElement->namespaceURI, 'mustUnderstand');
136
137
        return !empty($mustUnderstandAttr) && $visitor->visitBoolean($mustUnderstandAttr, [], $context);
0 ignored issues
show
Unused Code introduced by
The call to JMS\Serializer\XmlDeseri...Visitor::visitBoolean() has too many arguments starting with $context. ( Ignorable by Annotation )

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

137
        return !empty($mustUnderstandAttr) && $visitor->/** @scrutinizer ignore-call */ visitBoolean($mustUnderstandAttr, [], $context);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
138
    }
139
140
    public function serializeHeaderPlaceholder(XmlSerializationVisitor $visitor, object $data, array $type, SerializationContext $context): void
141
    {
142
        // serialize default headers
143
        $context->stopVisiting($data);
144
        $type = ['name' => $type['params'][0], 'params' => []];
145
        $context->getNavigator()->accept($data, $type, $context);
0 ignored issues
show
Unused Code introduced by
The call to JMS\Serializer\GraphNavigatorInterface::accept() has too many arguments starting with $context. ( Ignorable by Annotation )

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

145
        $context->getNavigator()->/** @scrutinizer ignore-call */ accept($data, $type, $context);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
146
        $context->startVisiting($data);
147
148
        // serialize additional headers
149
        $headerBag = $context->getAttribute('headers_outgoing');
150
        \assert($headerBag instanceof HeadersOutgoing);
151
152
        $factory = $context->getMetadataFactory();
153
        foreach ($headerBag->getHeaders() as $header) {
154
            $classMetadata = $factory->getMetadataForClass(get_class($header->getData()));
155
156
            $name = false !== ($pos = strpos($classMetadata->xmlRootName, ':')) ? substr($classMetadata->xmlRootName, $pos + 1) : $classMetadata->xmlRootName;
0 ignored issues
show
Bug introduced by
The property xmlRootName does not seem to exist on Metadata\ClassHierarchyMetadata.
Loading history...
157
158
            $metadata = new StaticPropertyMetadata($classMetadata->name, $name, $header->getData());
0 ignored issues
show
Bug introduced by
The property name does not seem to exist on Metadata\ClassHierarchyMetadata.
Loading history...
159
            $metadata->xmlNamespace = $classMetadata->xmlRootNamespace;
0 ignored issues
show
Bug introduced by
The property xmlRootNamespace does not seem to exist on Metadata\ClassHierarchyMetadata.
Loading history...
160
            $metadata->serializedName = $name;
161
162
            $visitor->visitProperty($metadata, $header->getData(), $context);
0 ignored issues
show
Unused Code introduced by
The call to JMS\Serializer\XmlSerial...isitor::visitProperty() has too many arguments starting with $context. ( Ignorable by Annotation )

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

162
            $visitor->/** @scrutinizer ignore-call */ 
163
                      visitProperty($metadata, $header->getData(), $context);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
163
164
            $this->handleOptions($visitor, $header->getOptions());
165
        }
166
    }
167
168
    public function serializeHeader(XmlSerializationVisitor $visitor, Header $header, array $type, SerializationContext $context): void
0 ignored issues
show
Unused Code introduced by
The parameter $type 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

168
    public function serializeHeader(XmlSerializationVisitor $visitor, Header $header, /** @scrutinizer ignore-unused */ array $type, SerializationContext $context): void

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...
169
    {
170
        $data = $header->getData();
171
        if ($data instanceof \DOMElement) {
172
            $importedNode = $data->ownerDocument !== $visitor->getDocument()
173
                ? $visitor->getDocument()->importNode($data, true)
174
                : $data;
175
            $visitor->getCurrentNode()->appendChild($importedNode);
176
        } else {
177
            $factory = $context->getMetadataFactory();
178
            /**
179
             * @var $classMetadata \JMS\Serializer\Metadata\ClassMetadata
180
             */
181
            $classMetadata = $factory->getMetadataForClass(get_class($header->getData()));
182
183
            $name = false !== ($pos = strpos($classMetadata->xmlRootName, ':')) ? substr($classMetadata->xmlRootName, $pos + 1) : $classMetadata->xmlRootName;
184
185
            $metadata = new StaticPropertyMetadata($classMetadata->name, $name, $header->getData());
186
            $metadata->xmlNamespace = $classMetadata->xmlRootNamespace;
187
            $metadata->serializedName = $name;
188
189
            $visitor->visitProperty($metadata, $data, $context);
0 ignored issues
show
Unused Code introduced by
The call to JMS\Serializer\XmlSerial...isitor::visitProperty() has too many arguments starting with $context. ( Ignorable by Annotation )

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

189
            $visitor->/** @scrutinizer ignore-call */ 
190
                      visitProperty($metadata, $data, $context);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
190
191
            $this->handleOptions($visitor, $header->getOptions());
192
        }
193
    }
194
195
    private function handleOptions(XmlSerializationVisitor $visitor, array $options): void
196
    {
197
        if (!count($options)) {
198
            return;
199
        }
200
201
        /**
202
         * @var $currentNode \DOMNode
203
         */
204
        $currentNode = $visitor->getCurrentNode();
205
        foreach ($options as $option => $value) {
206
            if (in_array($option, ['mustUnderstand', 'required', 'role', 'actor'])) {
207
                $this->setAttributeOnNode($currentNode->lastChild, $option, $value, $currentNode->ownerDocument->documentElement->namespaceURI);
208
            }
209
        }
210
    }
211
212
    /**
213
     * @param mixed $value
214
     */
215
    private function setAttributeOnNode(\DOMElement $node, string $name, $value, string $namespace): void
216
    {
217
        if (!($prefix = $node->lookupPrefix($namespace)) && !($prefix = $node->ownerDocument->lookupPrefix($namespace))) {
218
            $prefix = 'ns-' . substr(sha1($namespace), 0, 8);
219
        }
220
221
        $node->setAttributeNS($namespace, $prefix . ':' . $name, is_bool($value) || null === $value ? ($value ? 'true' : 'false') : $value);
222
    }
223
224
    public function deserializeFaultDetail(XmlDeserializationVisitor $visitor, \SimpleXMLElement $data, array $type, DeserializationContext $context): \SimpleXMLElement
0 ignored issues
show
Unused Code introduced by
The parameter $type 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

224
    public function deserializeFaultDetail(XmlDeserializationVisitor $visitor, \SimpleXMLElement $data, /** @scrutinizer ignore-unused */ array $type, DeserializationContext $context): \SimpleXMLElement

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...
Unused Code introduced by
The parameter $context 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

224
    public function deserializeFaultDetail(XmlDeserializationVisitor $visitor, \SimpleXMLElement $data, array $type, /** @scrutinizer ignore-unused */ DeserializationContext $context): \SimpleXMLElement

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...
Unused Code introduced by
The parameter $visitor 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

224
    public function deserializeFaultDetail(/** @scrutinizer ignore-unused */ XmlDeserializationVisitor $visitor, \SimpleXMLElement $data, array $type, DeserializationContext $context): \SimpleXMLElement

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...
225
    {
226
        return $data->children();
227
    }
228
}
229