Completed
Push — 5.3 ( 89941d...4b705f )
by Jeroen
23:30 queued 17:43
created

SlugRouter::getMasterRequest()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.0625

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 3
cts 4
cp 0.75
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
crap 2.0625
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
    public static $SLUG = '_slug';
28
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
     *
55
     * @deprecated in KunstmaanNodeBundle 5.1 and will be removed in KunstmaanNodeBundle 6.0.
56
     */
57
    protected $container;
58
59
    /** @var string */
60
    protected $slugPattern;
61
62
    /**
63
     * The constructor for this service
64
     *
65
     * @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...
66
     */
67 12 View Code Duplication
    public function __construct(
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...
68
        /* DomainConfigurationInterface */ $domainConfiguration,
69
        RequestStack $requestStack = null,
70
        EntityManagerInterface $em = null,
71
        $adminKey = null
72
    ) {
73 12
        $this->slugPattern = "[a-zA-Z0-9\-_\/]*";
74
75 12
        if ($domainConfiguration instanceof ContainerInterface) {
76 12
            @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 12
            $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 12
            $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 12
            $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 12
            $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 12
            $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 12
            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 2
    public function match($pathinfo)
105
    {
106 2
        $urlMatcher = new UrlMatcher(
107 2
            $this->getRouteCollection(),
108 2
            $this->getContext()
109
        );
110 2
        $result = $urlMatcher->match($pathinfo);
111
112 2
        if (!empty($result)) {
113 2
            $nodeTranslation = $this->getNodeTranslation($result);
114 2
            if (is_null($nodeTranslation)) {
115 1
                throw new ResourceNotFoundException('No page found for slug ' . $pathinfo);
116
            }
117 1
            $result['_nodeTranslation'] = $nodeTranslation;
118
        }
119
120 1
        return $result;
121
    }
122
123
    /**
124
     * Gets the request context.
125
     *
126
     * @return RequestContext The context
127
     *
128
     * @api
129
     */
130 10
    public function getContext()
131
    {
132 10
        if (!isset($this->context)) {
133
            /** @var Request $request */
134 9
            $request = $this->getMasterRequest();
135
136 9
            $this->context = new RequestContext();
137 9
            $this->context->fromRequest($request);
138
        }
139
140 10
        return $this->context;
141
    }
142
143
    /**
144
     * Sets the request context.
145
     *
146
     * @param RequestContext $context The context
147
     *
148
     * @api
149
     */
150 1
    public function setContext(RequestContext $context)
151
    {
152 1
        $this->context = $context;
153 1
    }
154
155
    /**
156
     * Generate an url for a supplied route.
157
     *
158
     * @param string   $name          The path
159
     * @param array    $parameters    The route parameters
160
     * @param int|bool $referenceType The type of reference to be generated (one of the UrlGeneratorInterface constants)
161
     *
162
     * @return null|string
163
     */
164 2
    public function generate($name, $parameters = array(), $referenceType = UrlGenerator::ABSOLUTE_PATH)
165
    {
166 2
        $this->urlGenerator = new UrlGenerator(
167 2
            $this->getRouteCollection(),
168 2
            $this->getContext()
169
        );
170
171 2
        return $this->urlGenerator->generate($name, $parameters, $referenceType);
0 ignored issues
show
Bug introduced by
It seems like $referenceType defined by parameter $referenceType on line 164 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...
172
    }
173
174
    /**
175
     * Getter for routeCollection
176
     *
177
     * @return \Symfony\Component\Routing\RouteCollection
178
     */
179 4
    public function getRouteCollection()
180
    {
181 4
        if (is_null($this->routeCollection)) {
182 4
            $this->routeCollection = new RouteCollection();
183
184 4
            $this->addPreviewRoute();
185 4
            $this->addSlugRoute();
186
        }
187
188 4
        return $this->routeCollection;
189
    }
190
191
    /**
192
     * @return null|\Symfony\Component\HttpFoundation\Request
193
     */
194 9
    protected function getMasterRequest()
195
    {
196 9
        if (is_null($this->requestStack)) {
197
            return null;
198
        }
199
200 9
        return $this->requestStack->getMasterRequest();
201
    }
202
203
    /**
204
     * Add the preview route to the route collection
205
     */
206 5
    protected function addPreviewRoute()
207
    {
208 5
        $routeParameters = $this->getPreviewRouteParameters();
209 5
        $this->addRoute(self::$SLUG_PREVIEW, $routeParameters);
210 5
    }
211
212
    /**
213
     * Add the slug route to the route collection
214
     */
215 4
    protected function addSlugRoute()
216
    {
217 4
        $routeParameters = $this->getSlugRouteParameters();
218 4
        $this->addRoute(self::$SLUG, $routeParameters);
219 4
    }
220
221
    /**
222
     * Return preview route parameters
223
     *
224
     * @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...
225
     */
226 11 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...
227
    {
228 11
        $previewPath = sprintf('/%s/preview/{url}', $this->adminKey);
229
        $previewDefaults = array(
230 11
            '_controller' => 'KunstmaanNodeBundle:Slug:slug',
231
            'preview' => true,
232 11
            'url' => '',
233 11
            '_locale' => $this->getDefaultLocale(),
234
        );
235
        $previewRequirements = array(
236 11
            'url' => $this->getSlugPattern(),
237
        );
238
239 11
        if ($this->isMultiLanguage()) {
240 8
            $previewPath = '/{_locale}' . $previewPath;
241 8
            unset($previewDefaults['_locale']);
242 8
            $previewRequirements['_locale'] = $this->getEscapedLocales($this->getBackendLocales());
243
        }
244
245
        return array(
246 11
            'path' => $previewPath,
247 11
            'defaults' => $previewDefaults,
248 11
            'requirements' => $previewRequirements,
249
        );
250
    }
251
252
    /**
253
     * Return slug route parameters
254
     *
255
     * @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...
256
     */
257 4 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...
258
    {
259 4
        $slugPath = '/{url}';
260
        $slugDefaults = array(
261 4
            '_controller' => 'KunstmaanNodeBundle:Slug:slug',
262
            'preview' => false,
263 4
            'url' => '',
264 4
            '_locale' => $this->getDefaultLocale(),
265
        );
266
        $slugRequirements = array(
267 4
            'url' => $this->getSlugPattern(),
268
        );
269
270 4
        if ($this->isMultiLanguage()) {
271 2
            $slugPath = '/{_locale}' . $slugPath;
272 2
            unset($slugDefaults['_locale']);
273 2
            $slugRequirements['_locale'] = $this->getEscapedLocales($this->getFrontendLocales());
274
        }
275
276
        return array(
277 4
            'path' => $slugPath,
278 4
            'defaults' => $slugDefaults,
279 4
            'requirements' => $slugRequirements,
280
        );
281
    }
282
283
    /**
284
     * @return bool
285
     */
286 11
    protected function isMultiLanguage($host = null)
287
    {
288 11
        return $this->domainConfiguration->isMultiLanguage($host);
289
    }
290
291
    /**
292
     * @return array
293
     */
294 7
    protected function getFrontendLocales()
295
    {
296 7
        return $this->domainConfiguration->getFrontendLocales();
297
    }
298
299
    /**
300
     * @return array
301
     */
302 8
    protected function getBackendLocales()
303
    {
304 8
        return $this->domainConfiguration->getBackendLocales();
305
    }
306
307
    /**
308
     * @return string
309
     */
310 11
    protected function getDefaultLocale()
311
    {
312 11
        return $this->domainConfiguration->getDefaultLocale();
313
    }
314
315
    /**
316
     * @return string
317
     */
318
    protected function getHost()
319
    {
320
        return $this->domainConfiguration->getHost();
321
    }
322
323
    /**
324
     * @return string
325
     */
326 11
    protected function getSlugPattern()
327
    {
328 11
        return $this->slugPattern;
329
    }
330
331
    /**
332
     * @param string $name
333
     * @param array  $parameters
334
     */
335 5 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...
336
    {
337 5
        $this->routeCollection->add(
338 5
            $name,
339 5
            new Route(
340 5
                $parameters['path'],
341 5
                $parameters['defaults'],
342 5
                $parameters['requirements']
343
            )
344
        );
345 5
    }
346
347
    /**
348
     * @param array $matchResult
349
     *
350
     * @return \Kunstmaan\NodeBundle\Entity\NodeTranslation
351
     */
352 2
    protected function getNodeTranslation($matchResult)
353
    {
354
        // The route matches, now check if it actually exists (needed for proper chain router chaining!)
355 2
        $nodeTranslationRepo = $this->getNodeTranslationRepository();
356
357
        /* @var NodeTranslation $nodeTranslation */
358 2
        $nodeTranslation = $nodeTranslationRepo->getNodeTranslationForUrl(
359 2
            $matchResult['url'],
360 2
            $matchResult['_locale']
361
        );
362
363 2
        return $nodeTranslation;
364
    }
365
366
    /**
367
     * @return \Kunstmaan\NodeBundle\Repository\NodeTranslationRepository
368
     */
369 4
    protected function getNodeTranslationRepository()
370
    {
371
        /* @var NodeTranslationRepository $nodeTranslationRepo */
372 4
        $nodeTranslationRepo = $this->em->getRepository(
373 4
            'KunstmaanNodeBundle:NodeTranslation'
374
        );
375
376 4
        return $nodeTranslationRepo;
377
    }
378
379
    /**
380
     * @param array $locales
381
     *
382
     * @return string
383
     */
384 8
    protected function getEscapedLocales($locales)
385
    {
386 8
        $escapedLocales = array();
387 8
        foreach ($locales as $locale) {
388 8
            $escapedLocales[] = str_replace('-', '\-', $locale);
389
        }
390
391 8
        return implode('|', $escapedLocales);
392
    }
393
}
394