Completed
Push — master ( 690c53...b92a26 )
by Kirill
03:02
created

AbstractDefinition   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 195
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 11

Test Coverage

Coverage 57.41%

Importance

Changes 0
Metric Value
wmc 26
lcom 1
cbo 11
dl 0
loc 195
ccs 31
cts 54
cp 0.5741
rs 10
c 0
b 0
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A typeOf() 0 14 3
A withOffset() 0 6 1
A withLine() 0 6 2
A withColumn() 0 6 2
A getDocument() 0 4 1
A getLine() 0 8 2
A getFile() 0 4 1
A getColumn() 0 8 2
A __toString() 0 4 1
A fetch() 0 13 3
A nameOf() 0 13 3
A fetchOrNull() 0 4 2
A error() 0 8 2
1
<?php
2
/**
3
 * This file is part of Railt package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
declare(strict_types=1);
9
10
namespace Railt\Reflection;
11
12
use Railt\Io\Exception\ExternalFileException;
13
use Railt\Io\Readable;
14
use Railt\Reflection\Common\Jsonable;
15
use Railt\Reflection\Common\Serializable;
16
use Railt\Reflection\Contracts\Definition;
17
use Railt\Reflection\Contracts\Definition\TypeDefinition;
18
use Railt\Reflection\Contracts\Document as DocumentInterface;
19
use Railt\Reflection\Contracts\Invocation\TypeInvocation;
20
use Railt\Reflection\Contracts\Type as TypeInterface;
21
use Railt\Reflection\Exception\ReflectionException;
22
23
/**
24
 * Class AbstractDefinition
25
 */
26
abstract class AbstractDefinition implements Definition, \JsonSerializable
27
{
28
    use Jsonable;
29
    use Serializable;
30
31
    /**
32
     * @var Document
33
     */
34
    protected $document;
35
36
    /**
37
     * @var int
38
     */
39
    protected $offset = 0;
40
41
    /**
42
     * @var int|null
43
     */
44
    protected $line;
45
46
    /**
47
     * @var int|null
48
     */
49
    protected $column;
50
51
    /**
52
     * AbstractDefinition constructor.
53
     * @param Document $document
54
     */
55 9
    public function __construct(Document $document)
56
    {
57 9
        $this->document = $document;
58 9
    }
59
60
    /**
61
     * @param TypeInterface|string $type
62
     * @return bool
63
     * @throws ReflectionException
64
     */
65
    public static function typeOf($type): bool
66
    {
67
        switch (true) {
68
            case $type instanceof TypeInterface:
69
                break;
70
            case \is_string($type):
71
                $type = Type::of($type);
72
                break;
73
            default:
74
                throw new ReflectionException('Unsupported argument');
75
        }
76
77
        return static::getType()->instanceOf($type);
78
    }
79
80
    /**
81
     * @param int $offset
82
     * @return Definition|TypeDefinition|TypeInvocation|$this
83
     */
84 1
    public function withOffset(int $offset): Definition
85
    {
86 1
        $this->offset = $offset;
87
88 1
        return $this;
89
    }
90
91
    /**
92
     * @param int $line
93
     * @return Definition|TypeDefinition|TypeInvocation|$this
94
     */
95 9
    public function withLine(?int $line): Definition
96
    {
97 9
        $this->line = \is_int($line) ? \max(1, $line) : $line;
98
99 9
        return $this;
100
    }
101
    /**
102
     * @param int $column
103
     * @return Definition|TypeDefinition|TypeInvocation|$this
104
     */
105
    public function withColumn(?int $column): Definition
106
    {
107
        $this->column = \is_int($column) ? \max(1, $column) : $column;
108
109
        return $this;
110
    }
111
112
    /**
113
     * @return DocumentInterface
114
     */
115 17
    public function getDocument(): DocumentInterface
116
    {
117 17
        return $this->document;
118
    }
119
120
    /**
121
     * @return int
122
     */
123 1
    public function getLine(): int
124
    {
125 1
        if ($this->line === null) {
126 1
            $this->line = $this->getFile()->getPosition($this->offset)->getLine();
127
        }
128
129 1
        return $this->line;
130
    }
131
132
    /**
133
     * @return Readable
134
     */
135 1
    public function getFile(): Readable
136
    {
137 1
        return $this->document->getFile();
138
    }
139
140
    /**
141
     * @return int
142
     */
143 2
    public function getColumn(): int
144
    {
145 2
        if ($this->column === null) {
146 2
            $this->column = $this->getFile()->getPosition($this->offset)->getColumn();
147
        }
148
149 2
        return $this->column;
150
    }
151
152
    /**
153
     * @return string
154
     */
155
    public function __toString(): string
156
    {
157
        return \sprintf('?<%s>', static::getType());
158
    }
159
160
    /**
161
     * @param string|TypeDefinition $type
162
     * @return TypeDefinition
163
     * @throws ExternalFileException
164
     */
165 10
    protected function fetch($type): TypeDefinition
166
    {
167
        switch (true) {
168 10
            case \is_string($type):
169 10
                return $this->document->getDictionary()->get($type, $this);
170
171 8
            case $type instanceof TypeDefinition:
172 8
                return $type;
173
        }
174
175
        throw (new ReflectionException('Unsupported argument'))
176
            ->throwsIn($this->getFile(), $this->getLine(), $this->getColumn());
177
    }
178
179
    /**
180
     * @param string|TypeDefinition $type
181
     * @return string|null
182
     * @throws ExternalFileException
183
     */
184 25
    protected function nameOf($type): ?string
185
    {
186
        switch (true) {
187 25
            case \is_string($type):
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
188 9
                return $type;
189
190 25
            case $type instanceof TypeDefinition:
191 25
                return $type->getName();
192
        }
193
194
        throw (new ReflectionException('Unsupported argument'))
195
            ->throwsIn($this->getFile(), $this->getLine(), $this->getColumn());
196
    }
197
198
    /**
199
     * @param string|TypeDefinition|null $type
200
     * @return null|TypeDefinition
201
     * @throws ExternalFileException
202
     */
203
    protected function fetchOrNull($type): ?TypeDefinition
204
    {
205
        return $type === null ? $this->fetch($type) : null;
206
    }
207
208
    /**
209
     * @param \Throwable $error
210
     * @return ExternalFileException
211
     */
212
    protected function error(\Throwable $error): ExternalFileException
213
    {
214
        if (! $error instanceof ExternalFileException) {
215
            $error = new ReflectionException($error->getMessage(), $error->getCode(), $error);
216
        }
217
218
        return $error->throwsIn($this->getFile(), $this->getLine(), $this->getColumn());
219
    }
220
}
221