Completed
Pull Request — 1.x (#6)
by Dorian
01:46
created

SubArrayHydratingHandler::getValidators()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 1
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 1
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 0
1
<?php
2
namespace MetaHydrator\Handler;
3
4
use MetaHydrator\Exception\HydratingException;
5
use MetaHydrator\Exception\ValidationException;
6
use MetaHydrator\Reflection\Getter;
7
use MetaHydrator\Reflection\GetterInterface;
8
use MetaHydrator\Validator\ValidatorInterface;
9
use Mouf\Hydrator\Hydrator;
10
11
/**
12
 * Class SubArrayHydratingHandler
13
 * @package MetaHydrator\Handler
14
 */
15
class SubArrayHydratingHandler implements HydratingHandlerInterface
16
{
17
    /** @var string */
18
    protected $key;
19
    public function getKey() { return $this->key; }
20
    public function setKey(string $key) { $this->key = $key; }
21
22
    /** @var string */
23
    protected $className;
24
    public function getClassName() { return $this->className; }
25
    public function setClassName(string $className) { $this->className = $className; }
26
27
    /** @var Hydrator */
28
    protected $hydrator;
29
    public function getHydrator() { return $this->hydrator; }
30
    public function setHydrator(Hydrator $hydrator) { $this->hydrator = $hydrator; }
31
32
    /** @var string */
33
    protected $errorMessage;
34
    public function getErrorMessage() { return $this->errorMessage; }
35
    public function setErrorMessage(string $errorMessage) { $this->errorMessage = $errorMessage; }
36
37
    /** @var string */
38
    private $subErrorMessage;
39
    public function getSubErrorMessage() { return $this->subErrorMessage; }
40
    public function setSubErrorMessage($subErrorMessage) { $this->subErrorMessage = $subErrorMessage; }
41
42
    /** @var ValidatorInterface[] */
43
    private $validators;
44
    public function getValidators() { return $this->validators; }
45
    public function setValidators(array $validators) { $this->validators = $validators; }
46
    public function addValidator(ValidatorInterface $validator) { $this->validators[] = $validator; }
47
48
    /** @var GetterInterface */
49
    protected $getter;
50
    public function getGetter() { return $this->getter; }
51
    public function setGetter(GetterInterface $getter) { $this->getter = $getter; }
52
53
    /** @var bool */
54
    private $associative;
55
    public function getAssociative() { return $this->associative; }
56
    public function setAssociative(bool $associative) { $this->associative = $associative; }
57
58
    /**
59
     * SubArrayHydratingHandler constructor.
60
     * @param string $key
61
     * @param string $className
62
     * @param Hydrator $hydrator
63
     * @param ValidatorInterface[] $validators
64
     * @param string $errorMessage
65
     * @param string $subErrorMessage
66
     * @param GetterInterface $getter
67
     * @param bool $associative
68
     */
69
    public function __construct(string $key, string $className, Hydrator $hydrator, array $validators = [], string $errorMessage = "", string $subErrorMessage = "", GetterInterface $getter = null, bool $associative = false)
70
    {
71
        $this->key = $key;
72
        $this->className = $className;
73
        $this->hydrator = $hydrator;
74
        $this->validators = $validators;
75
        $this->errorMessage = $errorMessage;
76
        $this->subErrorMessage = $subErrorMessage;
77
        $this->getter = $getter ?? new Getter(false);
78
        $this->associative = $associative;
79
    }
80
81
    /**
82
     * @param array $data
83
     * @param array $targetData
84
     * @param $object
85
     *
86
     * @throws HydratingException
87
     */
88
    public function handle(array $data, array &$targetData, $object = null)
89
    {
90
        if (!array_key_exists($this->key, $data)) {
91
            if ($object !== null) {
92
                return;
93
            } else {
94
                $subArray = null;
95
            }
96
        } elseif ($data[$this->key] === null) {
97
            $subArray = null;
98 View Code Duplication
        } elseif (!is_array($data[$this->key])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
99
            throw new HydratingException([$this->key => $this->errorMessage]);
100
        } else {
101
            $subArrayData = $data[$this->key];
102
            $subArray = $this->getSubArray($object) ?? null;
103
            $errorsMap = [];
104
            $ok = true;
105
            foreach ($subArrayData as $key => $subData) {
106
                $ok = $this->handleSub($key, $subData, $subArray, $errorsMap) && $ok;
0 ignored issues
show
Bug introduced by
It seems like $subArray defined by $this->getSubArray($object) ?? null on line 102 can also be of type null; however, MetaHydrator\Handler\Sub...ingHandler::handleSub() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
107
            }
108
            if (!$ok) {
109
                throw new HydratingException([$this->key => $errorsMap]);
110
            }
111
        }
112
113
        $this->validate($subArray, $object);
114
115
        if ($this->associative) {
116
            $targetData[$this->key] = $subArray;
117
        } elseif ($subArray !== null) {
118
            $targetData[$this->key] = array_values($subArray);
119
        } else {
120
            $targetData[$this->key] = null;
121
        }
122
    }
123
124
    /**
125
     * @param string $key
126
     * @param array|null $data
127
     * @param array $array
128
     * @param array $errorsMap
129
     * @return bool
130
     */
131
    protected function handleSub($key, $data, &$array, &$errorsMap)
132
    {
133
        if ($data === null) {
134
            if (array_key_exists($key, $array)) {
135
                unset($array[$key]);
136
            }
137
            $errorsMap[$key] = null;
138
            return true;
139
        }
140
        if (!is_array($data)) {
141
            $errorsMap[$key] = $this->subErrorMessage;
142
            return false;
143
        }
144
        if (isset($array[$key])) {
145
            $subObject = $array[$key];
146
            try {
147
                $this->hydrator->hydrateObject($data, $subObject);
148
                $errorsMap[$key] = null;
149
                return true;
150
            } catch (HydratingException $exception) {
151
                $errorsMap[$key] = $exception->getErrorsMap();
152
                return false;
153
            }
154
        } else {
155
            try {
156
                $subObject = $this->hydrator->hydrateNewObject($data, $this->className);
157
                $array[$key] = $subObject;
158
                $errorsMap[$key] = null;
159
                return true;
160
            } catch (HydratingException $exception) {
161
                $errorsMap[$key] = $exception->getErrorsMap();
162
                return false;
163
            }
164
        }
165
    }
166
167
    /**
168
     * @param $object
169
     * @return array
170
     */
171
    protected function getSubArray($object)
172
    {
173
        if ($object === null) {
174
            return [];
175
        }
176
        return $this->getter->get($object, $this->key);
177
    }
178
179
    /**
180
     * @param mixed $parsedValue
181
     * @param mixed $contextObject
182
     *
183
     * @throws HydratingException
184
     */
185 View Code Duplication
    private function validate($parsedValue, $contextObject = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
186
    {
187
        try {
188
            foreach ($this->validators as $validator) {
189
                $validator->validate($parsedValue, $contextObject);
190
            }
191
        } catch (ValidationException $exception) {
192
            throw new HydratingException([ $this->key => $exception->getInnerError() ]);
193
        }
194
    }
195
}
196