Passed
Push — master ( 10e07d...93334d )
by Sergey
03:08
created

Definition::renderDefineBlock()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2
Metric Value
dl 0
loc 9
ccs 5
cts 5
cp 1
rs 9.6666
cc 2
eloc 5
nc 2
nop 0
crap 2
1
<?php
2
/**
3
 * @author: Viskov Sergey
4
 * @date  : 19.03.16
5
 * @time  : 0:04
6
 */
7
8
namespace LTDBeget\sphinx\configurator\configurationEntities\base;
9
10
use InvalidArgumentException;
11
use LogicException;
12
use LTDBeget\sphinx\configurator\Configuration;
13
use LTDBeget\sphinx\configurator\exceptions\SectionException;
14
use LTDBeget\sphinx\enums\eSection;
15
16
/**
17
 * Class Definition
18
 *
19
 * @package LTDBeget\sphinx\configurator\configurationEntities\base
20
 */
21
abstract class Definition extends Section
22
{
23
    /**
24
     * Source constructor.
25
     *
26
     * @param Configuration $configuration
27
     * @param string        $name
28
     * @param string|null   $inheritance
29
     *
30
     * @throws InvalidArgumentException
31
     * @throws LogicException
32
     * @throws SectionException
33
     */
34 15
    public function __construct(
35
        Configuration $configuration,
36
        string $name,
37
        string $inheritance = NULL
38
    )
39
    {
40 15
        parent::__construct($configuration);
41
42 15
        $this->defineName($this->sanitizeName($name));
43
44 14
        if (!empty($inheritance)) {
45 11
            $this->setParent($this->sanitizeName($inheritance));
46
        }
47 13
    }
48
49
    /**
50
     * @return array
51
     * @throws \LogicException
52
     * @throws \LTDBeget\sphinx\configurator\exceptions\SectionException
53
     * @throws \InvalidArgumentException
54
     */
55 1
    public function toArray()
56
    {
57
        return [
1 ignored issue
show
Best Practice introduced by
The expression return array('type' => (...his->toArrayOptions()); seems to be an array, but some of its elements' types (null) are incompatible with the return type of the parent method LTDBeget\sphinx\configur...s\base\Section::toArray of type array<string,string|array>.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
58 1
            'type'        => (string) $this->getType(),
59 1
            'name'        => (string) $this->getName(),
60 1
            'inheritance' => $this->isHasInheritance() ? $this->getInheritance()->getName() : NULL,
61 1
            'options'     => $this->toArrayOptions()
62
        ];
63
    }
64
65
    /**
66
     * @return string
67
     * @throws \LTDBeget\sphinx\configurator\exceptions\SectionException
68
     * @throws \LogicException
69
     * @throws \InvalidArgumentException
70
     */
71 2
    protected function renderDefineBlock() : string
72
    {
73 2
        $string = "{$this->getType()} {$this->getName()}";
74 2
        if ($this->isHasInheritance()) {
75 2
            $string .= " : {$this->getInheritance()->getName()}";
76
        }
77
78 2
        return $string;
79
    }
80
81
    /**
82
     * @return bool
83
     */
84 10
    public function isHasInheritance() : bool
85
    {
86 10
        return NULL !== $this->inheritance;
87
    }
88
89
    /**
90
     * @return Definition
91
     * @throws LogicException
92
     * @throws InvalidArgumentException
93
     * @throws SectionException
94
     */
95 5
    public function getInheritance() : Definition
96
    {
97 5
        if (!$this->isHasInheritance()) {
98
            throw new SectionException("Trying to get inheritance for {$this->getType()} which doesn't' have it.");
99
        }
100
101 5
        return $this->inheritance;
102
    }
103
104
    /**
105
     * @return string
106
     */
107 12
    public function getName() : string
108
    {
109 12
        return $this->name;
110
    }
111
112
    /**
113
     * Delete option and its child
114
     *
115
     * @throws LogicException
116
     * @throws SectionException
117
     * @throws InvalidArgumentException
118
     */
119 2
    public function delete()
120
    {
121 2
        foreach ($this->getSelfTypeIterator() as $definition) {
122 2
            if ($definition->isHasInheritance() && $definition->getInheritance() === $this) {
123 2
                $definition->delete();
124
            }
125
        }
126
127 2
        parent::delete();
128 2
    }
129
130
    /**
131
     * @internal
132
     *
133
     * @param string $name
134
     *
135
     * @throws LogicException
136
     * @throws SectionException
137
     * @throws \InvalidArgumentException
138
     */
139 14
    private function defineName(string $name)
140
    {
141 14
        foreach ($this->getSelfTypeIterator() as $definition) {
142 12
            if ($definition->getName() === $name) {
143 12
                throw new SectionException("Duplicate name {$name} found in {$this->getType()} section");
144
            }
145
        }
146
147 14
        $this->name = $name;
148 14
    }
149
150
    /**
151
     * @internal
152
     *
153
     * @param string $inheritance
154
     *
155
     * @throws SectionException
156
     * @throws LogicException
157
     * @throws \InvalidArgumentException
158
     */
159 10
    private function setParent(string $inheritance)
160
    {
161 10
        foreach ($this->getSelfTypeIterator() as $definition) {
162 10
            if ($definition->getName() === $inheritance) {
163 10
                $this->inheritance = $definition;
164
            }
165
        }
166
167 10
        if (!$this->isHasInheritance()) {
168 2
            throw new SectionException("Inheritance with name {$inheritance} of section {$this->getType()} doesn't exists in configuration");
169
        }
170 8
    }
171
172
    /**
173
     * @internal
174
     *
175
     * @param string $name
176
     *
177
     * @return string
178
     * @throws \LogicException
179
     * @throws \InvalidArgumentException
180
     * @throws SectionException
181
     */
182 15
    private function sanitizeName(string $name) : string
183
    {
184 15
        $name = trim($name);
185
186 15
        if (empty($name)) {
187
            throw new SectionException("Name or inheritance of section {$this->getType()} can't be empty.");
188
        }
189
190 15
        if (!$this->isValidName($name)) {
191 2
            throw new SectionException("Name or inheritance of section {$this->getType()} must contains only A-Za-z and _ symbols");
192
        }
193
194 14
        return $name;
195
    }
196
197
    /**
198
     * @internal
199
     *
200
     * @param $name
201
     *
202
     * @return bool
203
     */
204 15
    private function isValidName($name) : bool
205
    {
206 15
        return (bool) preg_match("/^[A-Za-z_\d]*$/", $name);
207
    }
208
209
    /**
210
     * @internal
211
     *
212
     * @return Definition[]
213
     * @throws LogicException
214
     */
215 14
    private function getSelfTypeIterator()
216
    {
217 14
        switch ($this->getType()) {
218 14
            case eSection::INDEX:
219 8
                $iterator = $this->getConfiguration()->iterateIndex();
220 8
                break;
221 11
            case eSection::SOURCE:
222 11
                $iterator = $this->getConfiguration()->iterateSource();
223 11
                break;
224
            default:
225
                throw new LogicException("Unknown type {$this->getType()}");
226
        }
227
228 14
        return $iterator;
229
    }
230
231
    /**
232
     * @var string
233
     */
234
    private $name;
235
    /**
236
     * @var Definition
237
     */
238
    private $inheritance;
239
}