Parser   A
last analyzed

Complexity

Total Complexity 23

Size/Duplication

Total Lines 265
Duplicated Lines 0 %

Test Coverage

Coverage 94.92%

Importance

Changes 0
Metric Value
eloc 47
dl 0
loc 265
ccs 56
cts 59
cp 0.9492
rs 10
c 0
b 0
f 0
wmc 23

15 Methods

Rating   Name   Duplication   Size   Complexity  
A isParameterDynamic() 0 3 1
A addFormatter() 0 8 2
A setFormatters() 0 5 1
A boot() 0 4 1
A findFormatter() 0 3 1
A resolveFormatter() 0 15 3
A addFormatters() 0 7 2
A runForParameter() 0 18 2
A parse() 0 14 2
A getContainer() 0 3 1
A shouldParse() 0 4 2
A getMatches() 0 16 2
A setContainer() 0 5 1
A getFormatters() 0 3 1
A callFormatter() 0 3 1
1
<?php
2
3
namespace Lincable\Parsers;
4
5
use LogicException;
6
use Illuminate\Support\Collection;
7
use Lincable\Concerns\BuildClassnames;
8
use Lincable\Contracts\Formatters\Formatter;
9
use Illuminate\Contracts\Container\Container;
10
use Lincable\Contracts\Parsers\ParameterInterface;
11
use Lincable\Exceptions\NotDynamicOptionException;
12
13
abstract class Parser
14
{
15
    use BuildClassnames;
16
17
    /**
18
     * List with availables formatters.
19
     *
20
     * @var \Illuminate\Support\Collection
21
     */
22
    protected $formatters;
23
24
    /**
25
     * The application container implementation.
26
     *
27
     * @var \Illuminate\Contracts\Container\Container
28
     */
29
    protected $app;
30
31
    /**
32
     * Return the formatter call for the matches on parse.
33
     *
34
     * @param  array $matches
35
     * @return Lincable\Contracts\Parsers\ParameterInterface
0 ignored issues
show
Bug introduced by
The type Lincable\Parsers\Lincabl...sers\ParameterInterface was not found. Did you mean Lincable\Contracts\Parsers\ParameterInterface? If so, make sure to prefix the type with \.
Loading history...
36
     */
37
    abstract protected function parseMatches(array $matches): ParameterInterface;
38
39
    /**
40
     * Return the dynamic regex pattern.
41
     *
42
     * @return string
43
     */
44
    abstract protected function getDynamicPattern(): string;
45
46
    /**
47
     * Boot the parser with the container executing initial tasks.
48
     *
49
     * @param  \Illuminate\Contracts\Container\Container|null $app
50
     * @return void
51
     */
52 66
    public function boot(Container $app = null)
53
    {
54 66
        $this->formatters = collect();
55 66
        $this->app = $app;
56 66
    }
57
58
    /**
59
     * Push a new formatter to collection.
60
     *
61
     * @param  mixed $formatter
62
     * @param  string $name
63
     * @return this
64
     */
65 54
    public function addFormatter($formatter, string $name = null)
66
    {
67 54
        $this->formatters->put(
68 54
            $name ?: $this->nameFromClass($formatter, 'Formatter'),
69 54
            $formatter
70
        );
71
72 54
        return $this;
73
    }
74
75
    /**
76
     * Parse an option through formatters.
77
     *
78
     * @param  string $option
79
     * @return mixed
80
     * 
81
     * @throws Lincable\Exceptions\NotDynamicOption
82
     */
83 42
    public function parse(string $option)
84
    {
85 42
        if ($this->shouldParse($option)) {
86
87
            // Now that we have verified the option is dynamic and has
88
            // matches, we get the Option object from the implemented
89
            // method to deal with the matches.
90 41
            $parameter = $this->parseMatches($this->getMatches($option));
91
92
            // Return the content of the option executed.
93 41
            return $this->runForParameter($parameter);
94
        }
95
96 1
        throw new NotDynamicOptionException("Can not parse non dynamics parameter [$option].");
97
    }
98
99
    /**
100
     * Append a list of formatters.
101
     *
102
     * @param  mixed $formatters
103
     * @return this
104
     */
105 40
    public function addFormatters($formatters)
106
    {
107
        array_walk($formatters, function ($formatter, $name) {
108 40
            $this->addFormatter($formatter, is_int($name) ? null : $name);
109 40
        });
110
111 40
        return $this;
112
    }
113
114
    /**
115
     * Set the list with the new formatters.
116
     *
117
     * @param  \Illuminate\Support\Collection $formatters
118
     * @return this
119
     */
120
    public function setFormatters(Collection $formatters)
121
    {
122
        $this->formatters = $formatters;
123
124
        return $this;
125
    }
126
127
    /**
128
     * Return the formatters collection.
129
     *
130
     * @return \Illuminate\Support\Collection
131
     */
132 2
    public function getFormatters()
133
    {
134 2
        return $this->formatters;
135
    }
136
137
    /**
138
     * Return the containter instance.
139
     *
140
     * @return \Illuminate\Contracts\Container\Container
141
     */
142 39
    public function getContainer()
143
    {
144 39
        return $this->app;
145
    }
146
147
    /**
148
     * Set the new container instance.
149
     *
150
     * @param  \Illuminate\Contracts\Container\Container $app
151
     * @return this
152
     */
153 1
    public function setContainer(Container $app)
154
    {
155 1
        $this->app = $app;
156
157 1
        return $this;
158
    }
159
160
    /**
161
     * Return the first formatter that matches the option name.
162
     *
163
     * @param  string $option
164
     * @return mixed
165
     */
166 42
    public function findFormatter(string $option)
167
    {
168 42
        return $this->formatters->get($option);
169
    }
170
171
    /**
172
     * Determine wheter the parameter should be parsed.
173
     *
174
     * @param  string $option
175
     * @return bool
176
     */
177 42
    protected function shouldParse(string $option)
178
    {
179 42
        return $this->isParameterDynamic($option)
180 42
            && $this->getMatches($option);
181
    }
182
183
    /**
184
     * Run the parser for the parameter.
185
     *
186
     * @param  Lincable\Contracts\Parsers\ParameterInterface $parameter
187
     * @return mixed
188
     */
189 41
    protected function runForParameter(ParameterInterface $parameter)
190
    {
191
        // Get parameter value name.
192 41
        $name = $parameter->getValue();
193
194 41
        if ($formatter = $this->findFormatter($name)) {
195
196
            // Get a container callable.
197 39
            $callable = $this->resolveFormatter($formatter);
198
199
            // Execute the formatter class with the params.
200 39
            return $this->callFormatter(
201 39
                $callable,
202 39
                $parameter->getParams()
203
            );
204
        }
205
206 2
        throw new LogicException("Call to undefined formatter [{$name}].");
207
    }
208
209
    /**
210
     * Resolve the formatter call using the container with the array parameters.
211
     * The formatter argument should be a callable for the container.
212
     *
213
     * @param  mixed $formatter
214
     * @param  array $params
215
     * @return mixed
216
     */
217 39
    protected function callFormatter($formatter, array $params = [])
218
    {
219 39
        return $this->getContainer()->call($formatter, $params);
220
    }
221
222
    /**
223
     * Resolve a formatter to a container callable.
224
     *
225
     * @param  mixed $formatter
226
     * @return mixed
227
     */
228 39
    protected function resolveFormatter($formatter)
229
    {
230 39
        if (is_callable($formatter)) {
231
232
            // Just return the closure.
233 33
            return $formatter;
234
        }
235
236 19
        if (is_string($formatter)) {
237
238
            // Try to create formatter instance using dependency injection.
239 18
            $formatter = $this->getContainer()->make($formatter);
240
        }
241
242 19
        return [$formatter, 'format'];
243
    }
244
245
    /**
246
     * Determine wheter the parameter is dynamic.
247
     *
248
     * @param  string $parameter
249
     * @return bool
250
     */
251 47
    public function isParameterDynamic(string $parameter)
252
    {
253 47
        return (bool) preg_match($this->getDynamicPattern(), $parameter);
254
    }
255
256
    /**
257
     * Return the matches.
258
     *
259
     * @param  string $parameter
260
     * @return array
261
     */
262 45
    public function getMatches(string $parameter)
263
    {
264 45
        $isDynamic = preg_match(
265 45
            $this->getDynamicPattern(),
266 45
            $parameter,
267 45
            $matches
268
        );
269
270 45
        if ($isDynamic) {
271
272
            // The parameter is dynamic and has matches, so remove the first
273
            // match, that only matches the whole word.
274 45
            array_shift($matches);
275
        }
276
277 45
        return $matches;
278
    }
279
}
280