Completed
Push — master ( 770316...74fc07 )
by Jeroen
09:08 queued 02:44
created

Router/DomainBasedLocaleRouter.php (7 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Kunstmaan\MultiDomainBundle\Router;
4
5
use Kunstmaan\NodeBundle\Entity\NodeTranslation;
6
use Kunstmaan\NodeBundle\Router\SlugRouter;
7
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
8
use Symfony\Component\Routing\Generator\UrlGenerator;
9
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
10
use Symfony\Component\Routing\Matcher\UrlMatcher;
11
use Symfony\Component\Routing\Route;
12
use Symfony\Component\Routing\RouteCollection;
13
14
/**
15
 * Class DomainBasedLocaleRouter
16
 */
17
class DomainBasedLocaleRouter extends SlugRouter
18
{
19
    /** @var RouteCollection */
20
    protected $routeCollectionMultiLanguage;
21
22
    /**
23
     * @var string|null
24
     */
25
    private $otherSite;
26
27
    /**
28
     * @var array
29
     */
30
    private $cachedNodeTranslations = [];
31
32
    /**
33
     * Generate an url for a supplied route
34
     *
35
     * @param string   $name          The path
36
     * @param array    $parameters    The route parameters
37
     * @param int|bool $referenceType The type of reference to be generated (one of the UrlGeneratorInterface constants)
38
     *
39
     * @return null|string
40
     */
41 3
    public function generate($name, $parameters = array(), $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH)
42
    {
43 3
        if ('_slug' === $name && $this->isMultiLanguage() && $this->isMultiDomainHost()) {
44 3
            $locale = isset($parameters['_locale']) ? $parameters['_locale'] : $this->getRequestLocale();
45
46 3
            $reverseLocaleMap = $this->getReverseLocaleMap();
47 3
            if (isset($reverseLocaleMap[$locale])) {
48 3
                $parameters['_locale'] = $reverseLocaleMap[$locale];
49
            }
50
        }
51
52 3
        if (isset($parameters['otherSite'])) {
53 1
            $this->otherSite = $this->domainConfiguration->getFullHostById($parameters['otherSite']);
54
        } else {
55 3
            $this->otherSite = null;
56
        }
57
58 3
        $this->urlGenerator = new UrlGenerator(
59 3
            $this->getRouteCollection(),
60 3
            $this->getContext()
61
        );
62
63 3
        if (isset($parameters['otherSite'])) {
64 1
            unset($parameters['otherSite']);
65
        }
66
67 3
        return $this->urlGenerator->generate($name, $parameters, $referenceType);
0 ignored issues
show
It seems like $referenceType defined by parameter $referenceType on line 41 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...
68
    }
69
70
    /**
71
     * @param string $pathinfo
72
     *
73
     * @return array
74
     */
75 2
    public function match($pathinfo)
76
    {
77 2
        $urlMatcher = new UrlMatcher(
78 2
            $this->getRouteCollection(),
79 2
            $this->getContext()
80
        );
81
82 2
        $result = $urlMatcher->match($pathinfo);
83 2
        if (!empty($result)) {
84
            // Remap locale for front-end requests
85 2
            if ($this->isMultiDomainHost() &&
86 2
                $this->isMultiLanguage() &&
87 2
                !$result['preview']
88
            ) {
89 2
                $localeMap = $this->getLocaleMap();
90 2
                $locale = $result['_locale'];
91 2
                $result['_locale'] = $localeMap[$locale];
92
            }
93
94 2
            $nodeTranslation = $this->getNodeTranslation($result);
95 2
            if (\is_null($nodeTranslation)) {
96 1
                throw new ResourceNotFoundException(
97 1
                    'No page found for slug ' . $pathinfo
98
                );
99
            }
100 1
            $result['_nodeTranslation'] = $nodeTranslation;
101
        }
102
103 1
        return $result;
104
    }
105
106
    /**
107
     * @return string
108
     */
109 2
    protected function getRequestLocale()
110
    {
111 2
        $request = $this->getMasterRequest();
112 2
        $locale = $this->getDefaultLocale();
113 2
        if (!\is_null($request)) {
114 2
            $locale = $request->getLocale();
115
        }
116
117 2
        return $locale;
118
    }
119
120
    /**
121
     * @param array $matchResult
122
     *
123
     * @return \Kunstmaan\NodeBundle\Entity\NodeTranslation
124
     */
125 2
    protected function getNodeTranslation($matchResult)
126
    {
127 2
        $key = $matchResult['_controller'].$matchResult['url'].$matchResult['_locale'].$matchResult['_route'];
128 2
        if (!isset($this->cachedNodeTranslations[$key])) {
129 2
            $rootNode = $this->domainConfiguration->getRootNode();
130
131
            // Lookup node translation
132 2
            $nodeTranslationRepo = $this->getNodeTranslationRepository();
133
134
            /* @var NodeTranslation $nodeTranslation */
135 2
            $nodeTranslation = $nodeTranslationRepo->getNodeTranslationForUrl(
136 2
                $matchResult['url'],
137 2
                $matchResult['_locale'],
138 2
                false,
139 2
                null,
140 2
                $rootNode
141
            );
142 2
            $this->cachedNodeTranslations[$key] = $nodeTranslation;
143
        }
144
145 2
        return $this->cachedNodeTranslations[$key];
146
    }
147
148
    /**
149
     * @return bool
150
     */
151 5
    private function isMultiDomainHost()
152
    {
153 5
        return $this->domainConfiguration->isMultiDomainHost();
154
    }
155
156 6
    private function getHostLocales()
157
    {
158 6
        return $this->domainConfiguration->getFrontendLocales($this->otherSite['host']);
159
    }
160
161
    /**
162
     * @return array
163
     */
164 2
    private function getLocaleMap()
165
    {
166 2
        return array_combine(
167 2
            $this->getFrontendLocales(),
168 2
            $this->getBackendLocales()
169
        );
170
    }
171
172
    /**
173
     * @return array
174
     */
175 3
    private function getReverseLocaleMap()
176
    {
177 3
        return array_combine(
178 3
            $this->getBackendLocales(),
179 3
            $this->getFrontendLocales()
180
        );
181
    }
182
183
    /**
184
     * Getter for routeCollection
185
     *
186
     * Override slug router
187
     *
188
     * @return \Symfony\Component\Routing\RouteCollection
189
     */
190 7
    public function getRouteCollection()
191
    {
192 7
        if (($this->otherSite && $this->isMultiLanguage($this->otherSite['host'])) || (!$this->otherSite && $this->isMultiLanguage())) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->otherSite of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
Bug Best Practice introduced by
The expression $this->otherSite of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
193 6
            if (!$this->routeCollectionMultiLanguage) {
194 6
                $this->routeCollectionMultiLanguage = new RouteCollection();
195
196 6
                $this->addMultiLangPreviewRoute();
197 6
                $this->addMultiLangSlugRoute();
198
            }
199
200 6
            return $this->routeCollectionMultiLanguage;
201
        }
202
203 1
        if (!$this->routeCollection) {
204 1
            $this->routeCollection = new RouteCollection();
205
206 1
            $this->addPreviewRoute();
207 1
            $this->addSlugRoute();
208
        }
209
210 1
        return $this->routeCollection;
211
    }
212
213
    /**
214
     * Add the slug route to the route collection
215
     */
216 1
    protected function addSlugRoute()
217
    {
218 1
        $routeParameters = $this->getSlugRouteParameters();
219 1
        $this->addRoute('_slug', $routeParameters);
220 1
    }
221
222
    /**
223
     * Add the slug route to the route collection
224
     */
225 6
    protected function addMultiLangPreviewRoute()
226
    {
227 6
        $routeParameters = $this->getPreviewRouteParameters();
228 6
        $this->addMultiLangRoute('_slug_preview', $routeParameters);
229 6
    }
230
231
    /**
232
     * Add the slug route to the route collection multilanguage
233
     */
234 6
    protected function addMultiLangSlugRoute()
235
    {
236 6
        $routeParameters = $this->getSlugRouteParameters();
237 6
        $this->addMultiLangRoute('_slug', $routeParameters);
238 6
    }
239
240
    /**
241
     * @param string $name
242
     * @param array  $parameters
243
     */
244 6 View Code Duplication
    protected function addMultiLangRoute($name, array $parameters = array())
0 ignored issues
show
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...
245
    {
246 6
        $this->routeCollectionMultiLanguage->add(
247 6
            $name,
248 6
            new Route(
249 6
                $parameters['path'],
250 6
                $parameters['defaults'],
251 6
                $parameters['requirements']
252
            )
253
        );
254 6
    }
255
256
    /**
257
     * Return slug route parameters
258
     *
259
     * @return array
0 ignored issues
show
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...
260
     */
261 7
    protected function getSlugRouteParameters()
262
    {
263 7
        $slugPath = '/{url}';
264
        $slugDefaults = array(
265 7
            '_controller' => 'KunstmaanNodeBundle:Slug:slug',
266
            'preview' => false,
267 7
            'url' => '',
268 7
            '_locale' => $this->getDefaultLocale(),
269
        );
270
        $slugRequirements = array(
271 7
            'url' => $this->getSlugPattern(),
272
        );
273
274 7
        $locales = [];
275
276
        // If other site provided and multilingual, get the locales from the host config.
277 7
        if ($this->otherSite && $this->isMultiLanguage($this->otherSite['host'])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->otherSite of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
278 1
            $locales = $this->getHostLocales();
279 6
        } elseif ($this->isMultiLanguage() && !$this->otherSite) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->otherSite of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
280 5
            $locales = $this->getFrontendLocales();
281
        }
282
283
        // Make locale availables for the slug routes.
284 7
        if (!empty($locales)) {
285 6
            $slugPath = '/{_locale}' . $slugPath;
286 6
            unset($slugDefaults['_locale']);
287 6
            $slugRequirements['_locale'] = $this->getEscapedLocales($this->getHostLocales());
288
        }
289
290
        return array(
291 7
            'path' => $slugPath,
292 7
            'defaults' => $slugDefaults,
293 7
            'requirements' => $slugRequirements,
294
        );
295
    }
296
}
297