Passed
Pull Request — master (#6)
by Sergei
02:50 queued 13s
created

ClassDefinition::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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