UrlGenerator   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 320
Duplicated Lines 0 %

Test Coverage

Coverage 89.04%

Importance

Changes 0
Metric Value
eloc 62
dl 0
loc 320
ccs 65
cts 73
cp 0.8904
rs 10
c 0
b 0
f 0
wmc 22

17 Methods

Rating   Name   Duplication   Size   Complexity  
A getAvailableParsers() 0 3 1
A filterDynamicParameters() 0 19 1
A setCompiler() 0 5 1
A getModel() 0 7 2
A setParameterResolver() 0 5 1
A getUrlConf() 0 3 1
A injectFormatterToAvailableParsers() 0 18 3
A setModelFormatters() 0 12 1
A getCompiler() 0 3 1
A getParsers() 0 3 1
A forModel() 0 9 1
A getRawUrl() 0 3 1
A __construct() 0 9 2
A generate() 0 10 1
A guardModel() 0 12 2
A withParameterResolver() 0 3 1
A parseAvailableParsers() 0 15 1
1
<?php
2
3
namespace Lincable;
4
5
use RuntimeException;
6
use Lincable\Parsers\Parser;
7
use Illuminate\Support\Collection;
8
use Illuminate\Database\Eloquent\Model;
9
use Lincable\Contracts\Compilers\Compiler;
10
use Lincable\Exceptions\NoModelConfException;
11
12
class UrlGenerator
13
{
14
    /**
15
     * The model instance.
16
     *
17
     * @var \Illuminate\Database\Eloquent\Model
18
     */
19
    protected $model;
20
21
    /**
22
     * The parsers collection.
23
     *
24
     * @var \Illuminate\Support\Collection
25
     */
26
    protected $parsers;
27
28
    /**
29
     * The url configuration for models.
30
     *
31
     * @var \Lincable\UrlConf
32
     */
33
    protected $urlConf;
34
35
    /**
36
     * The compiler implementation.
37
     *
38
     * @var \Lincable\Contracts\Compilers\Compiler
39
     */
40
    protected $compiler;
41
42
    /**
43
     * The parsers available for the current model.
44
     *
45
     * @var \Illuminate\Support\Collection
46
     */
47
    protected $availableParsers;
48
49
    /**
50
     * The formatter resolver for dynamic parameters on model.
51
     *
52
     * @var mixed
53
     */
54
    protected static $parameterResolver;
55
56
    /**
57
     * Create a new class instance.
58
     *
59
     * @param  \Lincable\Contracts\Compilers\Compiler $compiler
60
     * @param  \Illuminate\Support\Collection $parsers
61
     * @param  \Lincable\UrlConf $urlConf
62
     * @return void
63
     */
64 47
    public function __construct(Compiler $compiler, Collection $parsers, UrlConf $urlConf)
65
    {
66 47
        if ($parsers->isEmpty()) {
67 1
            throw new RuntimeException('Parsers collection can not be empty.');
68
        }
69
70 46
        $this->parsers = $parsers;
71 46
        $this->urlConf = $urlConf;
72 46
        $this->compiler = $compiler;
73 46
    }
74
75
    /**
76
     * Set the current model to generate the url.
77
     *
78
     * @param  \Illuminate\Database\Eloquent\Model $model
79
     * @param  array $params
80
     * @return this
81
     */
82 34
    public function forModel(Model $model, array $params = [])
83
    {
84
        // Verify wheter we have the model fully configured on the url configuration.
85 34
        $this->guardModel($model);
86
87
        // Set the formatters for the model attributes.
88 33
        $this->setModelFormatters($params);
89
90 33
        return $this;
91
    }
92
93
    /**
94
     * Guard the model setting verifying wheter the model is also configured
95
     * on url configuration.
96
     *
97
     * @param  \Illuminate\Database\Eloquent\Model $model
98
     * @return void
99
     * 
100
     * @throws \Lincable\Exceptions\NoModelConfException
101
     */
102 34
    protected function guardModel(Model $model)
103
    {
104
        // The model class name.
105 34
        $className = get_class($model);
106
107 34
        if (! $this->urlConf->has($className)) {
108 1
            throw new NoModelConfException("Model [{$className}] is not configured. Check your lincable url configuration.");
109
        }
110
111
        // We assume the model is configured on url conf
112
        // then we can set the model for url generation.
113 33
        $this->model = $model;
114 33
    }
115
116
    /**
117
     * Add the formatters model parameters based on url dynamic parameters.
118
     *
119
     * @param  array $params
120
     * @return void
121
     */
122 33
    protected function setModelFormatters(array $customParams = [])
123
    {
124 33
        $attributes = $this->getModel()->getAttributes();
125
126
        // Merge model attributes with the an array on custom parameters.
127 33
        $parameters = array_merge($attributes, $customParams);
128
129
        // Filter only the parameters been used on url.
130 33
        $formatterParameters = $this->filterDynamicParameters($parameters);
131
132
        // Create the formatters for the dynamic parsers.
133 33
        $this->injectFormatterToAvailableParsers($formatterParameters);
134 33
    }
135
136
    /**
137
     * Generate the url for the current model.
138
     *
139
     * @return string
140
     */
141 32
    public function generate()
142
    {
143
        return $this->availableParsers->reduce(function ($url, Parser $parser) {
144
145
            // Set the compiler current parser.
146 32
            $this->compiler->setParser($parser);
147
148
            // Return the compiled url.
149 32
            return $this->compiler->compile($url);
150 32
        }, $this->getRawUrl());
151
    }
152
153
    /**
154
     * Return the raw model url.
155
     *
156
     * @return string
157
     */
158 33
    public function getRawUrl()
159
    {
160 33
        return $this->urlConf->get(get_class($this->getModel()));
161
    }
162
163
    /**
164
     * Return the model instance.
165
     *
166
     * @return \Illuminate\Database\Eloquent\Model
167
     * 
168
     * @throws \Exception
169
     */
170 33
    public function getModel()
171
    {
172 33
        if ($this->model) {
173 33
            return $this->model;
174
        }
175
176
        throw new \Exception('Any model related with generator');
177
    }
178
179
    /**
180
     * Return the compiler class instance.
181
     *
182
     * @return \Lincable\Contracts\Compilers\Compiler
183
     */
184
    public function getCompiler()
185
    {
186
        return $this->compiler;
187
    }
188
189
    /**
190
     * Return the collection parsers.
191
     *
192
     * @return \Illuminate\Support\Collection
193
     */
194 2
    public function getParsers()
195
    {
196 2
        return $this->parsers;
197
    }
198
199
    /**
200
     * Return the collection with available parsers for model.
201
     *
202
     * @return \Illuminate\Support\Collection
203
     */
204
    public function getAvailableParsers()
205
    {
206
        return $this->availableParsers;
207
    }
208
209
    /**
210
     * Return the model url configuration.
211
     *
212
     * @return \Lincable\UrlConf
213
     */
214 3
    public function getUrlConf()
215
    {
216 3
        return $this->urlConf;
217
    }
218
219
    /**
220
     * Set the function to resolve parameter formatter.
221
     *
222
     * @param  mixed $resolver
223
     * @return this
224
     */
225 1
    public function setParameterResolver($resolver)
226
    {
227 1
        static::withParameterResolver($resolver);
228
229 1
        return $this;
230
    }
231
232
    /**
233
     * Set the function to resolve parameter formatter globally.
234
     *
235
     * @param  mixed $resolver
236
     * @return void
237
     */
238 3
    public static function withParameterResolver($resolver)
239
    {
240 3
        static::$parameterResolver = $resolver;
241 3
    }
242
243
    /**
244
     * Set the compiler class instance.
245
     *
246
     * @param  \Lincable\Contracts\Compilers\Compiler
247
     * @return this
248
     */
249
    public function setCompiler(Compiler $compiler)
250
    {
251
        $this->compiler = $compiler;
252
253
        return $this;
254
    }
255
256
    /**
257
     * Return the filtered dynamic parameters to apply as a formatter
258
     * on the parsers classes.
259
     *
260
     * @param  array $parameters
261
     * @return array
262
     */
263 33
    protected function filterDynamicParameters(array $parameters)
264
    {
265 33
        $this->parseAvailableParsers();
266
267
        // Get the url configured for the model.
268 33
        $url = $this->getRawUrl();
269
270
        // Get all dynamic parameters on url from model parsers.
271
        $dynamics = $this->availableParsers->map(function (Parser $parser) use ($url) {
272
273
            // Set the current parser.
274 33
            $this->compiler->setParser($parser);
275
276 33
            return $this->compiler->parseDynamics($url);
277 33
        })->flatten()->all();
278
279
        return array_filter($parameters, function ($key) use ($dynamics) {
280 31
            return in_array($key, $dynamics);
281 33
        }, ARRAY_FILTER_USE_KEY);
282
    }
283
284
    /**
285
     * Add the formatter for the parameters on the parsers based on current model url.
286
     *
287
     * @param  array $dynamicParameters
288
     * @return void
289
     */
290 33
    protected function injectFormatterToAvailableParsers(array $dynamicParameters)
291
    {
292
        $this->availableParsers->each(function (Parser $parser) use ($dynamicParameters) {
293 33
            foreach ($dynamicParameters as $key => $value) {
294
295
                // Register the formatter for the key, and the logic function is to return
296
                $parser->addFormatter(function () use ($value, $key, $parser) {
297 31
                    if (static::$parameterResolver) {
298
299
                        // Get the container instance on parser class.
300 3
                        $container = $parser->getContainer();
301
302
                        // Call the parameter resolver for the value returned.
303 3
                        $value = $container->call(static::$parameterResolver, [$value, $key]);
304
                    }
305
306 31
                    return $value;
307 31
                }, $key);
308
            }
309 33
        });
310 33
    }
311
312
    /**
313
     * Generate the available parsers for the model.
314
     *
315
     * @return void
316
     */
317 33
    protected function parseAvailableParsers()
318
    {
319
        // Get the url configured for the model.
320 33
        $url = $this->getRawUrl();
321
322
        // Get parsers that has dynamic parameters for model url.
323
        $availableParsers = $this->parsers->filter(function (Parser $parser) use ($url) {
324
325
            // Change the current compiler parser.
326 33
            $this->compiler->setParser($parser);
327
328 33
            return $this->compiler->hasDynamics($url);
329 33
        });
330
331 33
        $this->availableParsers = clone $availableParsers;
332 33
    }
333
}
334