Passed
Pull Request — master (#93)
by Sergei
04:47 queued 02:36
created

ClassDefinition::resolve()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 23
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 5.0113

Importance

Changes 0
Metric Value
eloc 13
c 0
b 0
f 0
dl 0
loc 23
ccs 12
cts 13
cp 0.9231
rs 9.5222
cc 5
nc 5
nop 1
crap 5.0113
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Factory\Definition;
6
7
use Psr\Container\ContainerInterface;
8
use Throwable;
9
use Yiisoft\Factory\Exception\InvalidConfigException;
10
11
use function get_class;
12
use function gettype;
13
use function is_object;
14
15
/**
16
 * Reference points to a class name in the container
17
 */
18
class ClassDefinition implements DefinitionInterface
19
{
20
    private string $class;
21
    private bool $optional;
22
23
    /**
24
     * Constructor.
25
     *
26
     * @param string $class the class name
27
     * @param bool $optional if null should be returned instead of throwing an exception
28
     */
29 10
    public function __construct(string $class, bool $optional)
30
    {
31 10
        $this->class = $class;
32 10
        $this->optional = $optional;
33 10
    }
34
35 1
    public function getType(): string
36
    {
37 1
        return $this->class;
38
    }
39
40
    /**
41
     * @throws InvalidConfigException
42
     */
43 9
    public function resolve(ContainerInterface $container)
44
    {
45 9
        if ($this->isUnionType()) {
46
            return $this->resolveUnionType($container);
47
        }
48
49
        try {
50
            /** @var mixed */
51 9
            $result = $container->get($this->class);
52 5
        } catch (Throwable $t) {
53 5
            if ($this->optional) {
54 4
                return null;
55
            }
56 3
            throw $t;
57
        }
58
59 4
        if (!$result instanceof $this->class) {
60 1
            $actualType = $this->getValueType($result);
61 1
            throw new InvalidConfigException(
62 1
                "Container returned incorrect type \"$actualType\" for service \"$this->class\"."
63
            );
64
        }
65 3
        return $result;
66
    }
67
68
    /**
69
     * @throws Throwable
70
     *
71
     * @return mixed
72
     */
73
    private function resolveUnionType(ContainerInterface $container)
74
    {
75
        $types = explode('|', $this->class);
76
77
        foreach ($types as $type) {
78
            try {
79
                /** @var mixed */
80
                $result = $container->get($type);
81
                if (!$result instanceof $type) {
82
                    $actualType = $this->getValueType($result);
83
                    throw new InvalidConfigException(
84
                        "Container returned incorrect type \"$actualType\" for service \"$this->class\"."
85
                    );
86
                }
87
                return $result;
88
            } catch (Throwable $t) {
89
                $error = $t;
90
            }
91
        }
92
93
        if ($this->optional) {
94
            return null;
95
        }
96
97
        throw $error;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $error seems to be defined by a foreach iteration on line 77. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
98
    }
99
100 9
    private function isUnionType(): bool
101
    {
102 9
        return strpos($this->class, '|') !== false;
103
    }
104
105
    /**
106
     * @param mixed $value
107
     */
108 1
    private function getValueType($value): string
109
    {
110 1
        return is_object($value) ? get_class($value) : gettype($value);
111
    }
112
}
113