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

ClassDefinition   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 93
Duplicated Lines 0 %

Test Coverage

Coverage 59.46%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 15
eloc 34
c 2
b 0
f 0
dl 0
loc 93
ccs 22
cts 37
cp 0.5946
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A getValueType() 0 3 2
A resolveUnionType() 0 25 5
A __construct() 0 4 1
A resolve() 0 23 5
A isUnionType() 0 3 1
A getType() 0 3 1
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