ArgumentsReader::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace GoetasWebservices\SoapServices\Metadata\Arguments;
6
7
use Doctrine\Instantiator\Instantiator;
8
use GoetasWebservices\SoapServices\Metadata\SerializerUtils;
9
use JMS\Serializer\Accessor\DefaultAccessorStrategy;
10
use JMS\Serializer\DeserializationContext;
11
use JMS\Serializer\Metadata\PropertyMetadata;
12
use JMS\Serializer\Serializer;
13
14
class ArgumentsReader implements ArgumentsReaderInterface
15
{
16
    /**
17
     * @var Serializer
18
     */
19
    private $serializer;
20
21
    public function __construct(Serializer $serializer)
22
    {
23
        $this->serializer = $serializer;
24
    }
25
26
    /**
27
     * @param array $args
28
     * @param array $message
29
     */
30
    public function readArguments(array $args, array $message): object
31
    {
32
        $envelopes = array_filter($args, static function ($item) use ($message) {
33
            return $item instanceof $message['message_fqcn'];
34
        });
35
        if ($envelopes) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $envelopes of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
36
            $envelope = reset($envelopes);
37
            $this->handleHeaders($args, $message, $envelope);
38
39
            return $envelope;
40
        }
41
42
        $instantiator = new Instantiator();
43
        $envelope = $instantiator->instantiate($message['message_fqcn']);
44
        $this->handleHeaders($args, $message, $envelope);
45
46
        if (!count($message['parts'])) {
47
            return $envelope;
48
        }
49
50
        if ($args[0] instanceof $message['part_fqcn']) {
51
            $envelope->setBody($args[0]);
52
53
            return $envelope;
54
        }
55
56
        $body = $instantiator->instantiate($message['part_fqcn']);
57
        $envelope->setBody($body);
58
59
        $factory = SerializerUtils::getMetadataFactory($this->serializer);
60
61
        $classMetadata = $factory->getMetadataForClass($message['part_fqcn']);
62
63
        if (count($message['parts']) > 1) {
64
            if (count($message['parts']) !== count($args)) {
65
                throw new \Exception('Expected to have exactly ' . count($message['parts']) . ' arguments, supplied ' . count($args));
66
            }
67
68
            foreach ($message['parts'] as $paramName => $elementName) {
69
                $propertyMetadata = $classMetadata->propertyMetadata[$paramName];
0 ignored issues
show
Bug introduced by
The property propertyMetadata does not seem to exist on Metadata\ClassHierarchyMetadata.
Loading history...
70
                $this->setValue($body, array_shift($args), $propertyMetadata);
71
            }
72
73
            return $envelope;
74
        }
75
76
        $propertyName = key($message['parts']);
77
        $propertyMetadata = $classMetadata->propertyMetadata[$propertyName];
78
79
        if ($args[0] instanceof $propertyMetadata->type['name']) {
80
            $this->setValue($body, reset($args), $propertyMetadata);
81
82
            return $envelope;
83
        }
84
85
        $instance2 = $instantiator->instantiate($propertyMetadata->type['name']);
86
        $classMetadata2 = $factory->getMetadataForClass($propertyMetadata->type['name']);
87
        $this->setValue($body, $instance2, $propertyMetadata);
88
89
        foreach ($classMetadata2->propertyMetadata as $propertyMetadata2) {
90
            if (!count($args)) {
91
                throw new \Exception("Not enough arguments provided. Can't find a parameter to set " . $propertyMetadata2->name);
92
            }
93
94
            $value = array_shift($args);
95
            $this->setValue($instance2, $value, $propertyMetadata2);
96
        }
97
98
        return $envelope;
99
    }
100
101
    /**
102
     * @param array $args
103
     * @param array $message
104
     */
105
    private function handleHeaders(array $args, array $message, object $envelope): void
106
    {
107
        $headers = array_filter($args, static function ($item) use ($message) {
108
            return $item instanceof $message['headers_fqcn'];
109
        });
110
        if (count($headers)) {
111
            $envelope->setHeader(reset($headers));
112
        }
113
    }
114
115
    /**
116
     * @param mixed $value
117
     */
118
    private function setValue(object $target, $value, PropertyMetadata $propertyMetadata): void
119
    {
120
        $context = DeserializationContext::create();
121
        $accessor = new DefaultAccessorStrategy();
122
123
        $accessor->setValue($target, $value, $propertyMetadata, $context);
124
    }
125
}
126