Completed
Push — master ( 1bc0f1...9e20f7 )
by Sander
26:01
created

SlugRouter::__construct()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 26
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 26
rs 8.8571
c 0
b 0
f 0
cc 2
eloc 18
nc 2
nop 4
1
<?php
2
3
namespace Kunstmaan\NodeBundle\Router;
4
5
use Doctrine\ORM\EntityManagerInterface;
6
use Kunstmaan\AdminBundle\Helper\DomainConfigurationInterface;
7
use Kunstmaan\NodeBundle\Entity\NodeTranslation;
8
use Kunstmaan\NodeBundle\Repository\NodeTranslationRepository;
9
use Symfony\Component\DependencyInjection\ContainerInterface;
10
use Symfony\Component\HttpFoundation\Request;
11
use Symfony\Component\HttpFoundation\RequestStack;
12
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
13
use Symfony\Component\Routing\Generator\UrlGenerator;
14
use Symfony\Component\Routing\Matcher\UrlMatcher;
15
use Symfony\Component\Routing\RequestContext;
16
use Symfony\Component\Routing\Route;
17
use Symfony\Component\Routing\RouteCollection;
18
use Symfony\Component\Routing\RouterInterface;
19
20
/**
21
 * The SlugRouter takes care of routing the paths for slugs. It should have the
22
 * lowest priority as it's a catch-all router that routes (almost) all requests
23
 * to the SlugController
24
 */
25
class SlugRouter implements RouterInterface
26
{
27
28
    public static $SLUG = "_slug";
29
    public static $SLUG_PREVIEW = "_slug_preview";
30
31
    /** @var DomainConfigurationInterface */
32
    protected $domainConfiguration;
33
34
    /** @var RequestStack */
35
    private $requestStack;
36
37
    /** @var EntityManagerInterface */
38
    private $em;
39
40
    /** @var string */
41
    protected $adminKey;
42
43
    /** @var RequestContext */
44
    protected $context;
45
46
    /** @var RouteCollection */
47
    protected $routeCollection;
48
49
    /** @var UrlGenerator */
50
    protected $urlGenerator;
51
52
    /**
53
     * @var ContainerInterface
54
     * @deprecated in KunstmaanNodeBundle 5.1 and will be removed in KunstmaanNodeBundle 6.0.
55
     */
56
    protected $container;
57
58
    /** @var string */
59
    protected $slugPattern;
60
61
    /**
62
     * The constructor for this service
63
     *
64
     * @param ContainerInterface $container
0 ignored issues
show
Bug introduced by
There is no parameter named $container. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
65
     */
66
    public function __construct(
67
        /* DomainConfigurationInterface */ $domainConfiguration,
68
        RequestStack $requestStack = null,
69
        EntityManagerInterface $em = null,
70
        $adminKey = null
71
    )
72
    {
73
        $this->slugPattern = "[a-zA-Z0-9\-_\/]*";
74
75
        if ($domainConfiguration instanceof ContainerInterface) {
76
            @trigger_error('Container injection and the usage of the container is deprecated in KunstmaanNodeBundle 5.1 and will be removed in KunstmaanNodeBundle 6.0.', E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
77
78
            $this->container = $domainConfiguration;
0 ignored issues
show
Deprecated Code introduced by
The property Kunstmaan\NodeBundle\Router\SlugRouter::$container has been deprecated with message: in KunstmaanNodeBundle 5.1 and will be removed in KunstmaanNodeBundle 6.0.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
79
            $this->domainConfiguration = $this->container->get('kunstmaan_admin.domain_configuration');
0 ignored issues
show
Deprecated Code introduced by
The property Kunstmaan\NodeBundle\Router\SlugRouter::$container has been deprecated with message: in KunstmaanNodeBundle 5.1 and will be removed in KunstmaanNodeBundle 6.0.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
80
            $this->adminKey = $this->container->getParameter('kunstmaan_admin.admin_prefix');
0 ignored issues
show
Deprecated Code introduced by
The property Kunstmaan\NodeBundle\Router\SlugRouter::$container has been deprecated with message: in KunstmaanNodeBundle 5.1 and will be removed in KunstmaanNodeBundle 6.0.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
81
            $this->requestStack = $this->container->get('request_stack');
0 ignored issues
show
Deprecated Code introduced by
The property Kunstmaan\NodeBundle\Router\SlugRouter::$container has been deprecated with message: in KunstmaanNodeBundle 5.1 and will be removed in KunstmaanNodeBundle 6.0.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
82
            $this->em = $this->container->get('doctrine.orm.entity_manager');
0 ignored issues
show
Deprecated Code introduced by
The property Kunstmaan\NodeBundle\Router\SlugRouter::$container has been deprecated with message: in KunstmaanNodeBundle 5.1 and will be removed in KunstmaanNodeBundle 6.0.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
83
84
            return;
85
        }
86
87
        $this->domainConfiguration = $domainConfiguration;
88
        $this->adminKey = $adminKey;
89
        $this->requestStack = $requestStack;
90
        $this->em = $em;
91
    }
92
93
    /**
94
     * Match given urls via the context to the routes we defined.
95
     * This functionality re-uses the default Symfony way of routing and its
96
     * components
97
     *
98
     * @param string $pathinfo
99
     *
100
     * @throws ResourceNotFoundException
101
     *
102
     * @return array
103
     */
104
    public function match($pathinfo)
105
    {
106
        $urlMatcher = new UrlMatcher(
107
            $this->getRouteCollection(),
108
            $this->getContext()
109
        );
110
        $result = $urlMatcher->match($pathinfo);
111
112
        if (!empty($result)) {
113
            $nodeTranslation = $this->getNodeTranslation($result);
114
            if (is_null($nodeTranslation)) {
115
                throw new ResourceNotFoundException(
116
                    'No page found for slug ' . $pathinfo
117
                );
118
            }
119
            $result['_nodeTranslation'] = $nodeTranslation;
120
        }
121
122
        return $result;
123
    }
124
125
    /**
126
     * Gets the request context.
127
     *
128
     * @return RequestContext The context
129
     *
130
     * @api
131
     */
132
    public function getContext()
133
    {
134
        if (!isset($this->context)) {
135
            /** @var Request $request */
136
            $request = $this->getMasterRequest();
137
138
            $this->context = new RequestContext();
139
            $this->context->fromRequest($request);
140
        }
141
142
        return $this->context;
143
    }
144
145
    /**
146
     * Sets the request context.
147
     *
148
     * @param RequestContext $context The context
149
     *
150
     * @api
151
     */
152
    public function setContext(RequestContext $context)
153
    {
154
        $this->context = $context;
155
    }
156
157
    /**
158
     * Generate an url for a supplied route.
159
     *
160
     * @param string $name The path
161
     * @param array $parameters The route parameters
162
     * @param int|bool $referenceType The type of reference to be generated (one of the UrlGeneratorInterface constants)
163
     *
164
     * @return null|string
165
     */
166
    public function generate($name, $parameters = array(), $referenceType = UrlGenerator::ABSOLUTE_PATH)
167
    {
168
        $this->urlGenerator = new UrlGenerator(
169
            $this->getRouteCollection(),
170
            $this->getContext()
171
        );
172
173
        return $this->urlGenerator->generate($name, $parameters, $referenceType);
0 ignored issues
show
Bug introduced by
It seems like $referenceType defined by parameter $referenceType on line 166 can also be of type boolean; however, Symfony\Component\Routin...rlGenerator::generate() does only seem to accept integer, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
174
    }
175
176
    /**
177
     * Getter for routeCollection
178
     *
179
     * @return \Symfony\Component\Routing\RouteCollection
180
     */
181
    public function getRouteCollection()
182
    {
183
        if (is_null($this->routeCollection)) {
184
            $this->routeCollection = new RouteCollection();
185
186
            $this->addPreviewRoute();
187
            $this->addSlugRoute();
188
        }
189
190
        return $this->routeCollection;
191
    }
192
193
    /**
194
     * @return null|\Symfony\Component\HttpFoundation\Request
195
     */
196
    protected function getMasterRequest()
197
    {
198
        if (is_null($this->requestStack)) {
199
            return null;
200
        }
201
202
        return $this->requestStack->getMasterRequest();
203
    }
204
205
    /**
206
     * Add the preview route to the route collection
207
     */
208
    protected function addPreviewRoute()
209
    {
210
        $routeParameters = $this->getPreviewRouteParameters();
211
        $this->addRoute(self::$SLUG_PREVIEW, $routeParameters);
212
    }
213
214
    /**
215
     * Add the slug route to the route collection
216
     */
217
    protected function addSlugRoute()
218
    {
219
        $routeParameters = $this->getSlugRouteParameters();
220
        $this->addRoute(self::$SLUG, $routeParameters);
221
    }
222
223
    /**
224
     * Return preview route parameters
225
     *
226
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string|arra...>|array<string,string>>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
227
     */
228 View Code Duplication
    protected function getPreviewRouteParameters()
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...
229
    {
230
        $previewPath         = sprintf('/%s/preview/{url}', $this->adminKey);
231
        $previewDefaults     = array(
232
            '_controller' => 'KunstmaanNodeBundle:Slug:slug',
233
            'preview' => true,
234
            'url' => '',
235
            '_locale' => $this->getDefaultLocale()
236
        );
237
        $previewRequirements = array(
238
            'url' => $this->getSlugPattern()
239
        );
240
241
        if ($this->isMultiLanguage()) {
242
            $previewPath = '/{_locale}' . $previewPath;
243
            unset($previewDefaults['_locale']);
244
            $previewRequirements['_locale'] = $this->getEscapedLocales($this->getBackendLocales());
245
        }
246
247
        return array(
248
            'path' => $previewPath,
249
            'defaults' => $previewDefaults,
250
            'requirements' => $previewRequirements
251
        );
252
    }
253
254
    /**
255
     * Return slug route parameters
256
     *
257
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string|arra...>|array<string,string>>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
258
     */
259 View Code Duplication
    protected function getSlugRouteParameters()
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...
260
    {
261
        $slugPath = '/{url}';
262
        $slugDefaults = array(
263
            '_controller' => 'KunstmaanNodeBundle:Slug:slug',
264
            'preview' => false,
265
            'url' => '',
266
            '_locale' => $this->getDefaultLocale()
267
        );
268
        $slugRequirements = array(
269
            'url' => $this->getSlugPattern()
270
        );
271
272
        if ($this->isMultiLanguage()) {
273
            $slugPath = '/{_locale}' . $slugPath;
274
            unset($slugDefaults['_locale']);
275
            $slugRequirements['_locale'] = $this->getEscapedLocales($this->getFrontendLocales());
276
        }
277
278
        return array(
279
            'path' => $slugPath,
280
            'defaults' => $slugDefaults,
281
            'requirements' => $slugRequirements
282
        );
283
    }
284
285
    /**
286
     * @return boolean
287
     */
288
    protected function isMultiLanguage($host = null)
289
    {
290
        return $this->domainConfiguration->isMultiLanguage($host);
291
    }
292
293
    /**
294
     * @return array
295
     */
296
    protected function getFrontendLocales()
297
    {
298
        return $this->domainConfiguration->getFrontendLocales();
299
    }
300
301
    /**
302
     * @return array
303
     */
304
    protected function getBackendLocales()
305
    {
306
        return $this->domainConfiguration->getBackendLocales();
307
    }
308
309
    /**
310
     * @return string
311
     */
312
    protected function getDefaultLocale()
313
    {
314
        return $this->domainConfiguration->getDefaultLocale();
315
    }
316
317
    /**
318
     * @return string
319
     */
320
    protected function getHost()
321
    {
322
        return $this->domainConfiguration->getHost();
323
    }
324
325
    /**
326
     * @return string
327
     */
328
    protected function getSlugPattern()
329
    {
330
        return $this->slugPattern;
331
    }
332
333
    /**
334
     * @param string $name
335
     * @param array $parameters
336
     */
337 View Code Duplication
    protected function addRoute($name, array $parameters = array())
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...
338
    {
339
        $this->routeCollection->add(
340
            $name,
341
            new Route(
342
                $parameters['path'],
343
                $parameters['defaults'],
344
                $parameters['requirements']
345
            )
346
        );
347
    }
348
349
    /**
350
     * @param array $matchResult
351
     *
352
     * @return \Kunstmaan\NodeBundle\Entity\NodeTranslation
353
     */
354
    protected function getNodeTranslation($matchResult)
355
    {
356
        // The route matches, now check if it actually exists (needed for proper chain router chaining!)
357
        $nodeTranslationRepo = $this->getNodeTranslationRepository();
358
359
        /* @var NodeTranslation $nodeTranslation */
360
        $nodeTranslation = $nodeTranslationRepo->getNodeTranslationForUrl(
361
            $matchResult['url'],
362
            $matchResult['_locale']
363
        );
364
365
        return $nodeTranslation;
366
    }
367
368
    /**
369
     * @return \Kunstmaan\NodeBundle\Repository\NodeTranslationRepository
370
     */
371
    protected function getNodeTranslationRepository()
372
    {
373
        /* @var NodeTranslationRepository $nodeTranslationRepo */
374
        $nodeTranslationRepo = $this->em->getRepository(
375
            'KunstmaanNodeBundle:NodeTranslation'
376
        );
377
378
        return $nodeTranslationRepo;
379
    }
380
381
    /**
382
     * @param array $locales
383
     *
384
     * @return string
385
     */
386
    protected function getEscapedLocales($locales)
387
    {
388
        $escapedLocales = array();
389
        foreach ($locales as $locale) {
390
            $escapedLocales[] = str_replace('-', '\-', $locale);
391
        }
392
393
        return implode('|', $escapedLocales);
394
    }
395
}
396