Completed
Push — master ( 224f38...7a3326 )
by Asmir
38:41 queued 23:44
created

DefaultAccessorStrategy::setValue()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 31
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 6

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 6
eloc 20
c 2
b 0
f 0
nc 6
nop 4
dl 0
loc 31
ccs 4
cts 4
cp 1
crap 6
rs 8.9777
1
<?php
2
3
declare(strict_types=1);
4
5
namespace JMS\Serializer\Accessor;
6
7
use JMS\Serializer\DeserializationContext;
8
use JMS\Serializer\Exception\ExpressionLanguageRequiredException;
9
use JMS\Serializer\Exception\LogicException;
10
use JMS\Serializer\Expression\CompilableExpressionEvaluatorInterface;
11
use JMS\Serializer\Expression\Expression;
12
use JMS\Serializer\Expression\ExpressionEvaluatorInterface;
13
use JMS\Serializer\Metadata\ExpressionPropertyMetadata;
14
use JMS\Serializer\Metadata\PropertyMetadata;
15
use JMS\Serializer\Metadata\StaticPropertyMetadata;
16
use JMS\Serializer\SerializationContext;
17
18
/**
19
 * @author Asmir Mustafic <[email protected]>
20
 */
21
final class DefaultAccessorStrategy implements AccessorStrategyInterface
22
{
23
    /**
24
     * @var callable[]
25
     */
26
    private $readAccessors = [];
27
28
    /**
29
     * @var callable[]
30 333
     */
31
    private $writeAccessors = [];
32 333
33 333
    /**
34
     * @var \ReflectionProperty[]
35 172
     */
36
    private $propertyReflectionCache = [];
37 172
38 15
    /**
39
     * @var ExpressionEvaluatorInterface
40
     */
41 168
    private $evaluator;
42 6
43 2
    public function __construct(?ExpressionEvaluatorInterface $evaluator = null)
44
    {
45 4
        $this->evaluator = $evaluator;
46
    }
47
48 164
49 158
    /**
50 158
     * {@inheritdoc}
51
     */
52
    public function getValue(object $object, PropertyMetadata $metadata, SerializationContext $context)
53 4
    {
54 4
        if ($metadata instanceof StaticPropertyMetadata) {
55 4
            return $metadata->getValue(null);
0 ignored issues
show
Unused Code introduced by
The call to JMS\Serializer\Metadata\...rtyMetadata::getValue() has too many arguments starting with null. ( Ignorable by Annotation )

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

55
            return $metadata->/** @scrutinizer ignore-call */ getValue(null);

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...
56 4
        }
57 4
58
        if ($metadata instanceof ExpressionPropertyMetadata) {
59
            if (null === $this->evaluator) {
60 4
                throw new ExpressionLanguageRequiredException(sprintf('The property %s on %s requires the expression accessor strategy to be enabled.', $metadata->name, $metadata->class));
61 4
            }
62
63
            $variables = ['object' => $object, 'context' => $context, 'property_metadata' => $metadata];
64 156
65 156
            if (($metadata->expression instanceof Expression) && ($this->evaluator instanceof CompilableExpressionEvaluatorInterface)) {
66
                return $this->evaluator->evaluateParsed($metadata->expression, $variables);
67
            }
68
69 158
            return $this->evaluator->evaluate($metadata->expression, $variables);
70
        }
71
72 24
        if (null !== $metadata->getter) {
73
            return $object->{$metadata->getter}();
74
        }
75 64
76
        if ($metadata->forceReflectionAccess) {
77 64
            $ref = $this->propertyReflectionCache[$metadata->class][$metadata->name] ?? null;
78
            if (null === $ref) {
79
                $ref = new \ReflectionProperty($metadata->class, $metadata->name);
80
                $ref->setAccessible(true);
81 64
                $this->propertyReflectionCache[$metadata->class][$metadata->name] = $ref;
82 63
            }
83 63
84
            return $ref->getValue($object);
85 4
        }
86 4
87
        $accessor = $this->readAccessors[$metadata->class] ?? null;
88
        if (null === $accessor) {
89
            $accessor =\Closure::bind(static function ($o, $name) {
90
                return $o->$name;
91
            }, null, $metadata->class);
92 4
            $this->readAccessors[$metadata->class] = $accessor;
93 4
        }
94
95
        return $accessor($object, $metadata->name);
96 61
    }
97 61
98
    /**
99
     * {@inheritdoc}
100
     */
101 63
    public function setValue(object $object, $value, PropertyMetadata $metadata, DeserializationContext $context): void
102 63
    {
103
        if (true === $metadata->readOnly) {
104
            throw new LogicException(sprintf('%s on %s is read only.', $metadata->name, $metadata->class));
105 3
        }
106 3
107
        if (null !== $metadata->setter) {
108
            $object->{$metadata->setter}($value);
109
            return;
110
        }
111
112
        if ($metadata->forceReflectionAccess) {
113
            $ref = $this->propertyReflectionCache[$metadata->class][$metadata->name] ?? null;
114
            if (null === $ref) {
115
                $ref = new \ReflectionProperty($metadata->class, $metadata->name);
116
                $ref->setAccessible(true);
117
                $this->propertyReflectionCache[$metadata->class][$metadata->name] = $ref;
118
            }
119
120
            $ref->setValue($object, $value);
121
            return;
122
        }
123
124
        $accessor = $this->writeAccessors[$metadata->class] ?? null;
125
        if (null === $accessor) {
126
            $accessor = \Closure::bind(static function ($o, $name, $value): void {
127
                $o->$name = $value;
128
            }, null, $metadata->class);
129
            $this->writeAccessors[$metadata->class] = $accessor;
130
        }
131
        $accessor($object, $metadata->name, $value);
132
    }
133
}
134