Passed
Push — master ( 2944ee...dfe2d2 )
by Asmir
02:04
created

ArgumentsReader::readArguments()   B

Complexity

Conditions 10
Paths 10

Size

Total Lines 66
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 37
c 1
b 0
f 0
dl 0
loc 66
rs 7.6666
cc 10
nc 10
nop 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Arguments\Headers\Header;
9
use GoetasWebservices\SoapServices\Metadata\SerializerUtils;
10
use JMS\Serializer\Accessor\DefaultAccessorStrategy;
11
use JMS\Serializer\DeserializationContext;
12
use JMS\Serializer\Metadata\PropertyMetadata;
13
use JMS\Serializer\Serializer;
14
15
class ArgumentsReader implements ArgumentsReaderInterface
16
{
17
    /**
18
     * @var Serializer
19
     */
20
    private $serializer;
21
22
    public function __construct(Serializer $serializer)
23
    {
24
        $this->serializer = $serializer;
25
    }
26
27
    /**
28
     * @param array $args
29
     * @param array $message
30
     */
31
    public function readArguments(array $args, array $message): object
32
    {
33
        $envelope = array_filter($args, static function ($item) use ($message) {
34
            return $item instanceof $message['message_fqcn'];
35
        });
36
        if ($envelope) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $envelope 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...
37
            return reset($envelope);
38
        }
39
40
        $instantiator = new Instantiator();
41
        $envelope = $instantiator->instantiate($message['message_fqcn']);
42
43
        if (!count($message['parts'])) {
44
            return $envelope;
45
        }
46
47
        $args = $this->handleHeaders($args, $message, $envelope);
48
        if ($args[0] instanceof $message['part_fqcn']) {
49
            $envelope->setBody($args[0]);
50
51
            return $envelope;
52
        }
53
54
        $body = $instantiator->instantiate($message['part_fqcn']);
55
        $envelope->setBody($body);
56
57
        $factory = SerializerUtils::getMetadataFactory($this->serializer);
58
59
        $classMetadata = $factory->getMetadataForClass($message['part_fqcn']);
60
61
        if (count($message['parts']) > 1) {
62
            if (count($message['parts']) !== count($args)) {
63
                throw new \Exception('Expected to have exactly ' . count($message['parts']) . ' arguments, supplied ' . count($args));
64
            }
65
66
            foreach ($message['parts'] as $paramName => $elementName) {
67
                $propertyMetadata = $classMetadata->propertyMetadata[$paramName];
0 ignored issues
show
Bug introduced by
The property propertyMetadata does not seem to exist on Metadata\ClassHierarchyMetadata.
Loading history...
68
                $this->setValue($body, array_shift($args), $propertyMetadata);
69
            }
70
71
            return $envelope;
72
        }
73
74
        $propertyName = key($message['parts']);
75
        $propertyMetadata = $classMetadata->propertyMetadata[$propertyName];
76
77
        if ($args[0] instanceof $propertyMetadata->type['name']) {
78
            $this->setValue($body, reset($args), $propertyMetadata);
79
80
            return $envelope;
81
        }
82
83
        $instance2 = $instantiator->instantiate($propertyMetadata->type['name']);
84
        $classMetadata2 = $factory->getMetadataForClass($propertyMetadata->type['name']);
85
        $this->setValue($body, $instance2, $propertyMetadata);
86
87
        foreach ($classMetadata2->propertyMetadata as $propertyMetadata2) {
88
            if (!count($args)) {
89
                throw new \Exception("Not enough arguments provided. Can't find a parameter to set " . $propertyMetadata2->name);
90
            }
91
92
            $value = array_shift($args);
93
            $this->setValue($instance2, $value, $propertyMetadata2);
94
        }
95
96
        return $envelope;
97
    }
98
99
    /**
100
     * @param array $args
101
     * @param array $message
102
     *
103
     * @return array
104
     */
105
    private function handleHeaders(array $args, array $message, object $envelope): array
106
    {
107
        $headers = array_filter($args, static function ($item) use ($message) {
108
            return $item instanceof $message['headers_fqcn'];
109
        });
110
        if ($headers) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $headers 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...
111
            $envelope->setHeader(reset($headers));
112
        } else {
113
            $headers = array_filter($args, static function ($item) {
114
                return $item instanceof Header;
115
            });
116
            if (count($headers)) {
117
                $factory = SerializerUtils::getMetadataFactory($this->serializer);
118
                $classMetadata = $factory->getMetadataForClass($message['message_fqcn']);
119
                $propertyMetadata = $classMetadata->propertyMetadata['header'];
0 ignored issues
show
Bug introduced by
The property propertyMetadata does not seem to exist on Metadata\ClassHierarchyMetadata.
Loading history...
120
121
                $instantiator = new Instantiator();
122
                $header = $instantiator->instantiate($propertyMetadata->type['name']);
123
                foreach ($headers as $headerInfo) {
124
                    $header->addHeader($headerInfo);
125
                }
126
127
                $envelope->setHeader($header);
128
            }
129
        }
130
131
        $args = array_filter($args, static function ($item) use ($message) {
132
            return !($item instanceof Header) && !($item instanceof $message['headers_fqcn']);
133
        });
134
135
        return $args;
136
    }
137
138
    /**
139
     * @param mixed $value
140
     */
141
    private function setValue(object $target, $value, PropertyMetadata $propertyMetadata): void
142
    {
143
        $context = DeserializationContext::create();
144
        $accessor = new DefaultAccessorStrategy();
145
146
        $accessor->setValue($target, $value, $propertyMetadata, $context);
147
    }
148
}
149