Completed
Push — master ( 05a21e...215a06 )
by Nikola
03:52
created

Cascader::resolveArgument()   B

Complexity

Conditions 6
Paths 13

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 11
cts 11
cp 1
rs 8.6737
c 0
b 0
f 0
cc 6
eloc 12
nc 13
nop 2
crap 6
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cascader;
6
7
use BetterReflection\Reflection\ReflectionClass;
8
use BetterReflection\Reflector\Exception\IdentifierNotFound;
9
use Cascader\Exception\InvalidClassException;
10
use Cascader\Exception\InvalidOptionsException;
11
use Cascader\Exception\OptionNotSetException;
12
use BetterReflection\Reflection\ReflectionParameter;
13
use phpDocumentor\Reflection\Types\Object_;
14
15
class Cascader
16
{
17
    /**
18
     * @param string $className
19
     * @param array $options
20
     *
21
     * @throws InvalidClassException
22
     * @throws InvalidOptionsException
23
     *
24
     * @return object
25
     */
26 9
    public function create(string $className, array $options)
27
    {
28 9
        $reflectionClass = $this->getReflectionClass($className);
29 7
        $options = Options::fromArray($options);
30
31 6
        $arguments = $this->marshalArguments($reflectionClass, $options);
32
33 5
        return new $className(...$arguments);
34
    }
35
36 9
    protected function getReflectionClass(string $className)
37
    {
38
        try {
39 9
            $reflectionClass = ReflectionClass::createFromName($className);
40 1
        } catch (IdentifierNotFound $ex) {
41 1
            throw InvalidClassException::forNonExistingClass($className);
42
        }
43
44 8
        if (! $reflectionClass->isInstantiable()) {
45 1
            throw InvalidClassException::forNonInstantiableClass($className);
46
        }
47
48 7
        return $reflectionClass;
49
    }
50
51 6
    protected function marshalArguments(ReflectionClass $reflectionClass, Options $options) : array
52
    {
53 6
        if (! $reflectionClass->hasMethod('__construct')) {
54 1
            return [];
55
        }
56
57 5
        $arguments = [];
58
59 5
        $constructorParameters = $reflectionClass->getConstructor()->getParameters();
60
61 5
        foreach ($constructorParameters as $parameter) {
62 5
            $arguments[] = $this->resolveArgument($parameter, $options);
63
        }
64
65 4
        return $arguments;
66
    }
67
68 5
    protected function resolveArgument(ReflectionParameter $parameter, Options $options)
69
    {
70
        try {
71 5
            $argument = $options->get($parameter->getName());
72
73 4
            if (null !== ($parameterType = $parameter->getType())) {
74 4
                $parameterTypeObject = $parameterType->getTypeObject();
75
76 4
                if (is_array($argument) && $parameterTypeObject instanceof Object_) {
77 1
                    $argument = $this->create((string) $parameterTypeObject->getFqsen(), $argument);
78
                }
79
            }
80
81 4
            return $argument;
82 4
        } catch (OptionNotSetException $ex) {
83 4
            if (! $parameter->isOptional()) {
84 1
                throw InvalidOptionsException::forMissingMandatoryParameter($parameter);
85
            }
86
87 3
            return $parameter->getDefaultValue();
88
        }
89
    }
90
}
91