Issues (6)

src/FromToNativeTrait.php (1 issue)

Severity
1
<?php declare(strict_types=1);
2
/**
3
 * This file is part of the daikon-cqrs/interop project.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
9
namespace Daikon\Interop;
10
11
use ReflectionClass;
12
13
trait FromToNativeTrait
14
{
15
    use SupportsAnnotations;
16
17
    /**
18
     * @psalm-suppress MissingParamType
19
     * @return static
20
     */
21 11
    public static function fromNative($state): self
22
    {
23 11
        Assertion::isArray($state, 'This trait only works with array state.');
24
25 7
        list($valueFactories, $product) = static::construct($state);
26 6
        foreach ($valueFactories as $propertyName => $factory) {
27 4
            if (array_key_exists($propertyName, $state)) {
28 3
                $product->$propertyName = $factory($state[$propertyName]);
29 2
            } elseif (is_a($factory[0], MakeEmptyInterface::class, true)) {
30 2
                $product->$propertyName = ([$factory[0], 'makeEmpty'])();
31
            }
32
        }
33
34 4
        return $product;
35
    }
36
37
    public function toNative(): array
38
    {
39
        $state = [];
40
        $reflectionClass = new ReflectionClass($this);
41
        foreach (static::getInheritance() as $currentClass) {
42
            foreach ($currentClass->getProperties() as $property) {
43
                $propertyName = $property->getName();
44
                if ($currentClass->isTrait()) {
45
                    $property = $reflectionClass->getProperty($propertyName);
46
                }
47
                $property->setAccessible(true);
48
                $value = $property->getValue($this);
49
                if (is_a($value, ToNativeInterface::class)) {
50
                    $state[$propertyName] = $value->toNative();
51
                } else {
52
                    $state[$propertyName] = $value;
53
                }
54
            }
55
        }
56
57
        return $state;
58
    }
59
60 7
    private static function construct(array $payload): array
61
    {
62 7
        $valueFactories = static::inferValueFactories();
63 7
        $constructor = (new ReflectionClass(static::class))->getConstructor();
64 7
        if (is_null($constructor) || $constructor->getNumberOfParameters() === 0) {
65
            /** @psalm-suppress UnsafeInstantiation */
66 4
            return [$valueFactories, new static];
67
        }
68
69 4
        $constructorArgs = [];
70 4
        foreach ($constructor->getParameters() as $constructorParam) {
71 4
            $paramName = $constructorParam->getName();
72 4
            if (isset($payload[$paramName])) {
73 3
                if (isset($valueFactories[$paramName])) {
74
                    $constructorArgs[] = $valueFactories[$paramName]($payload[$paramName]);
75
                    unset($valueFactories[$paramName]);
76
                } else {
77 3
                    $constructorArgs[] = $payload[$paramName];
78
                }
79 3
            } elseif ($constructorParam->allowsNull()) {
80 3
                $constructorArgs[] = null;
81
            } else {
82
                throw new InvalidArgumentException(
83
                    "Missing required value for key '$paramName' while constructing from native state."
84
                );
85
            }
86
        }
87
88
        /**
89
         * @psalm-suppress UnsafeInstantiation
90
         * @psalm-suppress TooManyArguments
91
         */
92 4
        return [$valueFactories, new static(...$constructorArgs)];
0 ignored issues
show
The call to Daikon\Interop\FromToNativeTrait::__construct() has too many arguments starting with $constructorArgs. ( Ignorable by Annotation )

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

92
        return [$valueFactories, /** @scrutinizer ignore-call */ new static(...$constructorArgs)];

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...
93
    }
94
}
95