Passed
Push — master ( b678cc...5a9a7b )
by Pieter
03:14
created

MethodCallDenormalizer::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 3
c 1
b 0
f 1
nc 1
nop 3
dl 0
loc 8
rs 10
1
<?php
2
3
4
namespace W2w\Lib\ApieObjectAccessNormalizer\Normalizers;
5
6
use ReflectionClass;
7
use ReflectionMethod;
8
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
9
use Symfony\Component\Serializer\Normalizer\ContextAwareDenormalizerInterface;
10
use W2w\Lib\ApieObjectAccessNormalizer\NameConverters\NullNameConverter;
11
use W2w\Lib\ApieObjectAccessNormalizer\ObjectAccess\ObjectAccessInterface;
12
13
/**
14
 * Special denormalizer to call a reflection method and return the value back.
15
 *
16
 * Usage:
17
 * - type: ReflectionMethod::ClassWithNameSpace::method
18
 * - context['object-instance'] object to run method on
19
 * - context['initial-arguments'] already hydrated arguments with key = variable name.
20
 * - context['object-access'] used object access instance.
21
 */
22
class MethodCallDenormalizer implements ContextAwareDenormalizerInterface
23
{
24
    /**
25
     * @var ObjectAccessInterface
26
     */
27
    private $objectAccess;
28
29
    /**
30
     * @var ApieObjectAccessNormalizer
31
     */
32
    private $normalizer;
33
34
    /**
35
     * @var NameConverterInterface
36
     */
37
    private $nameConverter;
38
39
    public function __construct(
40
        ObjectAccessInterface $objectAccess,
41
        ApieObjectAccessNormalizer $normalizer,
42
        NameConverterInterface $nameConverter = null
43
    ) {
44
        $this->objectAccess = $objectAccess;
45
        $this->normalizer = $normalizer;
46
        $this->nameConverter = $nameConverter ?? new NullNameConverter();
47
    }
48
49
    /**
50
     * {@inheritDoc}
51
     */
52
    public function supportsDenormalization($data, $type, $format = null, array $context = [])
53
    {
54
        if (strpos($type, 'ReflectionMethod::') !== 0) {
55
            return false;
56
        }
57
        return isset($context['object-instance']);
58
    }
59
60
    /**
61
     * {@inheritDoc}
62
     */
63
    public function denormalize($data, $type, $format = null, array $context = [])
64
    {
65
        if (!isset($context['key_prefix'])) {
66
            $context['key_prefix'] = '';
67
        }
68
        $method = new ReflectionMethod(substr($type, strlen('ReflectionMethod::')));
0 ignored issues
show
Bug introduced by
The call to ReflectionMethod::__construct() has too few arguments starting with name. ( Ignorable by Annotation )

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

68
        $method = /** @scrutinizer ignore-call */ new ReflectionMethod(substr($type, strlen('ReflectionMethod::')));

This check compares calls to functions or methods with their respective definitions. If the call has less 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...
69
        $objectAccess = $context['object_access'] ?? $this->objectAccess;
70
        $arguments = $objectAccess->getMethodArguments($method, new ReflectionClass($context['object-instance']));
71
        $initialArguments = $context['initial-arguments'] ?? [];
72
        $returnObject = $initialArguments;
73
        foreach ($arguments as $denormalizedFieldName => $type) {
0 ignored issues
show
introduced by
$type is overwriting one of the parameters of this function.
Loading history...
74
            $fieldName = $this->nameConverter->normalize($denormalizedFieldName, $type, $format, $context);
0 ignored issues
show
Unused Code introduced by
The call to Symfony\Component\Serial...rInterface::normalize() has too many arguments starting with $type. ( Ignorable by Annotation )

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

74
            /** @scrutinizer ignore-call */ 
75
            $fieldName = $this->nameConverter->normalize($denormalizedFieldName, $type, $format, $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...
75
            if (isset($initialArguments[$fieldName])) {
76
                continue;
77
            }
78
            $returnObject[$fieldName] = $this->normalizer->denormalizeType($data, $denormalizedFieldName, $fieldName, $type, $format, $context);
79
        }
80
        return $method->invokeArgs($context['object-instance'], $returnObject);
81
    }
82
}
83