Completed
Push — master ( 6f1a19...e34473 )
by Vitaly
02:18
created

Inject::checkInheritanceViolation()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 14
ccs 0
cts 0
cp 0
rs 9.4285
cc 3
eloc 8
nc 2
nop 2
crap 12
1
<?php
2
declare(strict_types = 1);
3
4
/**
5
 * Created by PhpStorm.
6
 * User: root
7
 * Date: 27.07.2016
8
 * Time: 1:55.
9
 */
10
namespace samsonframework\container\annotation;
11
12
use samsonframework\container\metadata\PropertyMetadata;
13
14
/**
15
 * Injection annotation class.
16
 *
17
 * @Annotation
18
 */
19
class Inject extends CollectionValue implements PropertyInterface
20
{
21
    /** @var string Injectable dependency */
22
    protected $dependency;
23 1
24
    /**
25 1
     * Inject constructor.
26 1
     *
27
     * @param array $valueOrValues
28
     */
29 5
    public function __construct(array $valueOrValues)
30
    {
31
        parent::__construct($valueOrValues);
32 5
33
        // Get first argument from annotation
34
        $this->dependency = $this->collection[0] ?? null;
35 5
36 1
        // Removed first namespace separator if present
37
        $this->dependency = is_string($this->dependency) ? ltrim($this->dependency, '\\') : $this->dependency;
38
    }
39
40 5
    /** {@inheritdoc} */
41 1
    public function toPropertyMetadata(PropertyMetadata $propertyMetadata)
42
    {
43
        // Get @Inject("value")
44
        $propertyMetadata->dependency = $this->dependency;
45 5
46 1
        $this->validate(
47
            $propertyMetadata->typeHint,
48
            $propertyMetadata->dependency,
49 4
            $propertyMetadata->classMetadata->nameSpace
50 1
        );
51
    }
52 3
53
    /**
54
     * Validate dependency.
55
     *
56
     * @param string $type
57
     * @param string $dependency
58
     * @param string $namespace
59
     */
60
    protected function validate(&$type, &$dependency, $namespace)
61 5
    {
62
        $dependency = $this->buildFullClassName($dependency, $namespace);
63
        $type = $this->buildFullClassName($type, $namespace);
64 5
65 3
        // Check for inheritance violation
66 3
        if ($this->checkInheritanceViolation($type, $dependency)) {
67
            throw new \InvalidArgumentException(
68
                '@Inject dependency violates ' . $type . ' inheritance with ' . $dependency
69 2
            );
70
        }
71
72
        if ($this->checkInterfaceWithoutClassName($type, $dependency)) {
73
            throw new \InvalidArgumentException(
74
                'Cannot @Inject interface, inherited class name should be specified
75
                ');
76
        }
77
78
        // Empty @Inject with type hint - use type hine as dependency
79 4
        if ($dependency === null && $type !== null) {
80
            $dependency = $type;
81 4
        }
82 4
    }
83 4
84
    /**
85
     * Build full class name.
86
     *
87
     * @param string $className Full or short class name
88
     * @param string $namespace Name space
89
     *
90
     * @return string Full class name
91
     */
92 View Code Duplication
    protected function buildFullClassName($className, $namespace)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
93
    {
94
        // Check if we need to append namespace to dependency
95
        if ($className !== null && strpos($className, '\\') === false) {
96
            return $namespace . '\\' . $className;
97
        }
98
99
        return $className;
100
    }
101
102
    /**
103
     * Check if @Inject violates inheritance.
104
     *
105
     * @param string $type       Property/Parameter type
106
     * @param string $dependency @Inject value
107
     *
108
     * @return bool True if @Inject violates inheritance
109
     */
110
    protected function checkInheritanceViolation($type, $dependency) : bool
111
    {
112
        // Check for inheritance violation
113
        if ($dependency !== null && $type !== null) {
114
            $inheritance = array_merge(
115
                [$dependency],
116
                class_parents($dependency),
117
                class_implements($dependency)
118
            );
119
            return !in_array($type, $inheritance, true);
120
        }
121
122
        return false;
123
    }
124
125
    /**
126
     * Check if @Inject has no class name and type hint is interface.
127
     *
128
     * @param string $type       Property/Parameter type
129
     * @param string $dependency @Inject value
130
     *
131
     * @return bool True if @Inject has no class name and type hint is interface.
132
     */
133
    protected function checkInterfaceWithoutClassName($type, $dependency) : bool
134
    {
135
        return $type !== null
136
        && $dependency === null
137
        && (new \ReflectionClass($type))->isInterface();
138
    }
139
}
140