Completed
Push — master ( 1de9b7...830752 )
by Kristof
38:46 queued 24:09
created

Router/DomainBasedLocaleRouter.php (5 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
    public function generate($name, $parameters = array(), $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH)
42
    {
43
        if ('_slug' === $name) {
44
            if ($this->isMultiLanguage() && $this->isMultiDomainHost()) {
45
                $locale = isset($parameters['_locale']) ? $parameters['_locale'] : $this->getRequestLocale();
46
47
                $reverseLocaleMap = $this->getReverseLocaleMap();
48
                if (isset($reverseLocaleMap[$locale])) {
49
                    $parameters['_locale'] = $reverseLocaleMap[$locale];
50
                }
51
            }
52
        }
53
54
        if (isset($parameters['otherSite'])) {
55
            $this->otherSite = $this->domainConfiguration->getFullHostById($parameters['otherSite']);
56
        } else {
57
            $this->otherSite = null;
58
        }
59
60
        $this->urlGenerator = new UrlGenerator(
61
            $this->getRouteCollection(),
62
            $this->getContext()
63
        );
64
65
        if (isset($parameters['otherSite'])) {
66
            unset($parameters['otherSite']);
67
        }
68
69
        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...
70
    }
71
72
    /**
73
     * @param string $pathinfo
74
     *
75
     * @return array
76
     */
77
    public function match($pathinfo)
78
    {
79
        $urlMatcher = new UrlMatcher(
80
            $this->getRouteCollection(),
81
            $this->getContext()
82
        );
83
84
        $result = $urlMatcher->match($pathinfo);
85
        if (!empty($result)) {
86
            // Remap locale for front-end requests
87
            if ($this->isMultiDomainHost() &&
88
                $this->isMultiLanguage() &&
89
                !$result['preview']
90
            ) {
91
                $localeMap = $this->getLocaleMap();
92
                $locale = $result['_locale'];
93
                $result['_locale'] = $localeMap[$locale];
94
            }
95
96
            $nodeTranslation = $this->getNodeTranslation($result);
97
            if (is_null($nodeTranslation)) {
98
                throw new ResourceNotFoundException(
99
                    'No page found for slug ' . $pathinfo
100
                );
101
            }
102
            $result['_nodeTranslation'] = $nodeTranslation;
103
        }
104
105
        return $result;
106
    }
107
108
    /**
109
     * @return string
110
     */
111
    protected function getRequestLocale()
112
    {
113
        $request = $this->getMasterRequest();
114
        $locale = $this->getDefaultLocale();
115
        if (!is_null($request)) {
116
            $locale = $request->getLocale();
117
        }
118
119
        return $locale;
120
    }
121
122
    /**
123
     * @param array $matchResult
124
     *
125
     * @return \Kunstmaan\NodeBundle\Entity\NodeTranslation
126
     */
127
    protected function getNodeTranslation($matchResult)
128
    {
129
        $key = $matchResult['_controller'].$matchResult['url'].$matchResult['_locale'].$matchResult['_route'];
130
        if (!isset($this->cachedNodeTranslations[$key])) {
131
            $rootNode = $this->domainConfiguration->getRootNode();
132
133
            // Lookup node translation
134
            $nodeTranslationRepo = $this->getNodeTranslationRepository();
135
136
            /* @var NodeTranslation $nodeTranslation */
137
            $nodeTranslation = $nodeTranslationRepo->getNodeTranslationForUrl(
138
                $matchResult['url'],
139
                $matchResult['_locale'],
140
                false,
141
                null,
142
                $rootNode
143
            );
144
            $this->cachedNodeTranslations[$key] = $nodeTranslation;
145
        }
146
147
        return $this->cachedNodeTranslations[$key];
148
    }
149
150
    /**
151
     * @return bool
152
     */
153
    private function isMultiDomainHost()
154
    {
155
        return $this->domainConfiguration->isMultiDomainHost();
156
    }
157
158
    private function getHostLocales()
159
    {
160
        return $this->domainConfiguration->getFrontendLocales($this->otherSite['host']);
161
    }
162
163
    /**
164
     * @return array
165
     */
166
    private function getLocaleMap()
167
    {
168
        return array_combine(
169
            $this->getFrontendLocales(),
170
            $this->getBackendLocales()
171
        );
172
    }
173
174
    /**
175
     * @return array
176
     */
177
    private function getReverseLocaleMap()
178
    {
179
        return array_combine(
180
            $this->getBackendLocales(),
181
            $this->getFrontendLocales()
182
        );
183
    }
184
185
    /**
186
     * Getter for routeCollection
187
     *
188
     * Override slug router
189
     *
190
     * @return \Symfony\Component\Routing\RouteCollection
191
     */
192
    public function getRouteCollection()
193
    {
194
        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...
195
            if (!$this->routeCollectionMultiLanguage) {
196
                $this->routeCollectionMultiLanguage = new RouteCollection();
197
198
                $this->addMultiLangPreviewRoute();
199
                $this->addMultiLangSlugRoute();
200
            }
201
202
            return $this->routeCollectionMultiLanguage;
203
        } elseif (!$this->routeCollection) {
204
            $this->routeCollection = new RouteCollection();
205
206
            $this->addPreviewRoute();
207
            $this->addSlugRoute();
208
        }
209
210
        return $this->routeCollection;
211
    }
212
213
    /**
214
     * Add the slug route to the route collection
215
     */
216
    protected function addSlugRoute()
217
    {
218
        $routeParameters = $this->getSlugRouteParameters();
219
        $this->addRoute('_slug', $routeParameters);
220
    }
221
222
    /**
223
     * Add the slug route to the route collection
224
     */
225
    protected function addMultiLangPreviewRoute()
226
    {
227
        $routeParameters = $this->getPreviewRouteParameters();
228
        $this->addMultiLangRoute('_slug_preview', $routeParameters);
229
    }
230
231
    /**
232
     * Add the slug route to the route collection multilanguage
233
     */
234
    protected function addMultiLangSlugRoute()
235
    {
236
        $routeParameters = $this->getSlugRouteParameters();
237
        $this->addMultiLangRoute('_slug', $routeParameters);
238
    }
239
240
    /**
241
     * @param string $name
242
     * @param array  $parameters
243
     */
244 View Code Duplication
    protected function addMultiLangRoute($name, array $parameters = array())
245
    {
246
        $this->routeCollectionMultiLanguage->add(
247
            $name,
248
            new Route(
249
                $parameters['path'],
250
                $parameters['defaults'],
251
                $parameters['requirements']
252
            )
253
        );
254
    }
255
256
    /**
257
     * Return slug route parameters
258
     *
259
     * @return array
260
     */
261
    protected function getSlugRouteParameters()
262
    {
263
        $slugPath = '/{url}';
264
        $slugDefaults = array(
265
            '_controller' => 'KunstmaanNodeBundle:Slug:slug',
266
            'preview' => false,
267
            'url' => '',
268
            '_locale' => $this->getDefaultLocale(),
269
        );
270
        $slugRequirements = array(
271
            'url' => $this->getSlugPattern(),
272
        );
273
274
        $locales = [];
275
276
        // If other site provided and multilingual, get the locales from the host config.
277
        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
            $locales = $this->getHostLocales();
279
        } 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
            $locales = $this->getFrontendLocales();
281
        }
282
283
        // Make locale availables for the slug routes.
284
        if (!empty($locales)) {
285
            $slugPath = '/{_locale}' . $slugPath;
286
            unset($slugDefaults['_locale']);
287
            $slugRequirements['_locale'] = $this->getEscapedLocales($this->getHostLocales());
288
        }
289
290
        return array(
291
            'path' => $slugPath,
292
            'defaults' => $slugDefaults,
293
            'requirements' => $slugRequirements,
294
        );
295
    }
296
}
297