Completed
Push — EZP-29014-sorting-url-list ( 1ca57c )
by
unknown
26:07
created

URLAliasService   D

Complexity

Total Complexity 87

Size/Duplication

Total Lines 735
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Importance

Changes 0
Metric Value
dl 0
loc 735
rs 4.4444
c 0
b 0
f 0
wmc 87
lcom 1
cbo 8

21 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 1
B createUrlAlias() 0 28 3
C createGlobalUrlAlias() 0 45 7
C listLocationAliases() 0 63 10
A compareUrlAliases() 0 4 1
C selectAliasLanguageCode() 0 25 7
B extractPath() 0 34 4
B choosePrioritizedLanguageCode() 0 16 5
B matchPath() 0 29 4
A matchLanguageCode() 0 10 3
B sortTranslationsByPrioritizedLanguages() 0 22 4
C isUrlAliasLoadable() 0 30 8
B isPathLoadable() 0 20 5
B listGlobalAliases() 0 26 3
B removeAliases() 0 22 4
A buildSPIUrlAlias() 0 11 1
A lookup() 0 13 3
D reverseLookup() 0 40 10
A load() 0 16 2
A cleanUrl() 0 4 1
A buildUrlAliasDomainObject() 0 16 1

How to fix   Complexity   

Complex Class

Complex classes like URLAliasService often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use URLAliasService, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * File containing the eZ\Publish\Core\Repository\URLAliasService class.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributed with this source code.
8
 */
9
namespace eZ\Publish\Core\Repository;
10
11
use eZ\Publish\API\Repository\URLAliasService as URLAliasServiceInterface;
12
use eZ\Publish\API\Repository\Repository as RepositoryInterface;
13
use eZ\Publish\SPI\Persistence\Content\UrlAlias\Handler;
14
use eZ\Publish\API\Repository\Values\Content\Location;
15
use eZ\Publish\API\Repository\Values\Content\URLAlias;
16
use eZ\Publish\SPI\Persistence\Content\URLAlias as SPIURLAlias;
17
use eZ\Publish\Core\Base\Exceptions\NotFoundException;
18
use eZ\Publish\Core\Base\Exceptions\InvalidArgumentException;
19
use eZ\Publish\API\Repository\Exceptions\ForbiddenException;
20
use Exception;
21
22
/**
23
 * URLAlias service.
24
 *
25
 * @example Examples/urlalias.php
26
 */
27
class URLAliasService implements URLAliasServiceInterface
28
{
29
    /**
30
     * @var \eZ\Publish\API\Repository\Repository
31
     */
32
    protected $repository;
33
34
    /**
35
     * @var \eZ\Publish\SPI\Persistence\Content\UrlAlias\Handler
36
     */
37
    protected $urlAliasHandler;
38
39
    /**
40
     * @var array
41
     */
42
    protected $settings;
43
44
    /**
45
     * Setups service with reference to repository object that created it & corresponding handler.
46
     *
47
     * @param \eZ\Publish\API\Repository\Repository $repository
48
     * @param \eZ\Publish\SPI\Persistence\Content\UrlAlias\Handler $urlAliasHandler
49
     * @param array $settings
50
     */
51
    public function __construct(RepositoryInterface $repository, Handler $urlAliasHandler, array $settings = array())
52
    {
53
        $this->repository = $repository;
54
        $this->urlAliasHandler = $urlAliasHandler;
55
        // Union makes sure default settings are ignored if provided in argument
56
        $this->settings = $settings + array(
57
            'showAllTranslations' => false,
58
        );
59
        // Get prioritized languages from language service to not have to call it several times
60
        $this->settings['prioritizedLanguageList'] = $repository->getContentLanguageService()->getPrioritizedLanguageCodeList();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface eZ\Publish\API\Repository\LanguageService as the method getPrioritizedLanguageCodeList() does only exist in the following implementations of said interface: eZ\Publish\Core\Repository\LanguageService.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
61
    }
62
63
    /**
64
     * Create a user chosen $alias pointing to $location in $languageCode.
65
     *
66
     * This method runs URL filters and transformers before storing them.
67
     * Hence the path returned in the URLAlias Value may differ from the given.
68
     * $alwaysAvailable makes the alias available in all languages.
69
     *
70
     * @param \eZ\Publish\API\Repository\Values\Content\Location $location
71
     * @param string $path
72
     * @param bool $forwarding if true a redirect is performed
73
     * @param string $languageCode the languageCode for which this alias is valid
74
     * @param bool $alwaysAvailable
75
     *
76
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if the path already exists for the given language
77
     *
78
     * @return \eZ\Publish\API\Repository\Values\Content\URLAlias
79
     */
80
    public function createUrlAlias(Location $location, $path, $languageCode, $forwarding = false, $alwaysAvailable = false)
81
    {
82
        $path = $this->cleanUrl($path);
83
84
        $this->repository->beginTransaction();
85
        try {
86
            $spiUrlAlias = $this->urlAliasHandler->createCustomUrlAlias(
87
                $location->id,
88
                $path,
89
                $forwarding,
90
                $languageCode,
91
                $alwaysAvailable
92
            );
93
            $this->repository->commit();
94
        } catch (ForbiddenException $e) {
95
            $this->repository->rollback();
96
            throw new InvalidArgumentException(
97
                '$path',
98
                $e->getMessage(),
99
                $e
100
            );
101
        } catch (Exception $e) {
102
            $this->repository->rollback();
103
            throw $e;
104
        }
105
106
        return $this->buildUrlAliasDomainObject($spiUrlAlias, $path);
107
    }
108
109
    /**
110
     * Create a user chosen $alias pointing to a resource in $languageCode.
111
     *
112
     * This method does not handle location resources - if a user enters a location target
113
     * the createCustomUrlAlias method has to be used.
114
     * This method runs URL filters and and transformers before storing them.
115
     * Hence the path returned in the URLAlias Value may differ from the given.
116
     *
117
     * $alwaysAvailable makes the alias available in all languages.
118
     *
119
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if the path already exists for the given
120
     *         language or if resource is not valid
121
     *
122
     * @param string $resource
123
     * @param string $path
124
     * @param string $languageCode
125
     * @param bool $forwarding
126
     * @param bool $alwaysAvailable
127
     *
128
     * @return \eZ\Publish\API\Repository\Values\Content\URLAlias
129
     */
130
    public function createGlobalUrlAlias($resource, $path, $languageCode, $forwarding = false, $alwaysAvailable = false)
131
    {
132
        if (!preg_match('#^([a-zA-Z0-9_]+):(.+)$#', $resource, $matches)) {
133
            throw new InvalidArgumentException('$resource', 'argument is not valid');
134
        }
135
136
        $path = $this->cleanUrl($path);
137
138
        if ($matches[1] === 'eznode' || 0 === strpos($resource, 'module:content/view/full/')) {
139
            if ($matches[1] === 'eznode') {
140
                $locationId = $matches[2];
141
            } else {
142
                $resourcePath = explode('/', $matches[2]);
143
                $locationId = end($resourcePath);
144
            }
145
146
            return $this->createUrlAlias(
147
                $this->repository->getLocationService()->loadLocation($locationId),
148
                $path,
149
                $languageCode,
150
                $forwarding,
151
                $alwaysAvailable
152
            );
153
        }
154
155
        $this->repository->beginTransaction();
156
        try {
157
            $spiUrlAlias = $this->urlAliasHandler->createGlobalUrlAlias(
158
                $matches[1] . ':' . $this->cleanUrl($matches[2]),
159
                $path,
160
                $forwarding,
161
                $languageCode,
162
                $alwaysAvailable
163
            );
164
            $this->repository->commit();
165
        } catch (ForbiddenException $e) {
166
            $this->repository->rollback();
167
            throw new InvalidArgumentException('$path', $e->getMessage(), $e);
168
        } catch (Exception $e) {
169
            $this->repository->rollback();
170
            throw $e;
171
        }
172
173
        return $this->buildUrlAliasDomainObject($spiUrlAlias, $path);
174
    }
175
176
    /**
177
     * List of url aliases pointing to $location, sorted by language priority.
178
     *
179
     * @param \eZ\Publish\API\Repository\Values\Content\Location $location
180
     * @param bool $custom if true the user generated aliases are listed otherwise the autogenerated
181
     * @param string $languageCode filters those which are valid for the given language
182
     * @param null|bool $showAllTranslations
183
     * @param null|string[] $prioritizedLanguageList
184
     *
185
     * @return \eZ\Publish\API\Repository\Values\Content\URLAlias[]
186
     */
187
    public function listLocationAliases(
188
        Location $location,
189
        $custom = true,
190
        $languageCode = null,
191
        $showAllTranslations = null,
192
        array $prioritizedLanguageList = null
193
    ) {
194
        $spiUrlAliasList = $this->urlAliasHandler->listURLAliasesForLocation(
195
            $location->id,
196
            $custom
197
        );
198
        if ($showAllTranslations === null) {
199
            $showAllTranslations = $this->settings['showAllTranslations'];
200
        }
201
        if ($prioritizedLanguageList === null) {
202
            $prioritizedLanguageList = $this->settings['prioritizedLanguageList'];
203
        }
204
        $urlAliasList = array();
205
206
        foreach ($spiUrlAliasList as $spiUrlAlias) {
207
            if (
208
                !$this->isUrlAliasLoadable(
209
                    $spiUrlAlias,
210
                    $languageCode,
211
                    $showAllTranslations,
212
                    $prioritizedLanguageList
213
                )
214
            ) {
215
                continue;
216
            }
217
218
            $path = $this->extractPath(
219
                $spiUrlAlias,
220
                $languageCode,
221
                $showAllTranslations,
222
                $prioritizedLanguageList
223
            );
224
225
            if ($path === false) {
226
                continue;
227
            }
228
229
            $urlAliasList[$spiUrlAlias->id] = $this->buildUrlAliasDomainObject($spiUrlAlias, $path);
230
        }
231
232
        $prioritizedAliasList = array();
233
        foreach ($prioritizedLanguageList as $languageCode) {
234
            foreach ($urlAliasList as $urlAlias) {
235
                foreach ($urlAlias->languageCodes as $aliasLanguageCode) {
236
                    if ($aliasLanguageCode === $languageCode) {
237
                        $prioritizedAliasList[$urlAlias->id] = $urlAlias;
238
                        break;
239
                    }
240
                }
241
            }
242
        }
243
244
        usort($prioritizedAliasList, [$this, 'compareUrlAliases']);
245
        usort($urlAliasList, [$this, 'compareUrlAliases']);
246
247
        // Add aliases not matched by prioritized language to the end of the list
248
        return array_values($prioritizedAliasList + $urlAliasList);
249
    }
250
251
    /**
252
     * @param \eZ\Publish\API\Repository\Values\Content\URLAlias $firstAlias
253
     * @param \eZ\Publish\API\Repository\Values\Content\URLAlias $secondAlias
254
     *
255
     * @return int
256
     */
257
    private function compareUrlAliases(URLAlias $firstAlias, URLAlias $secondAlias)
258
    {
259
        return strnatcasecmp($firstAlias->path, $secondAlias->path);
260
    }
261
262
    /**
263
     * Determines alias language code.
264
     *
265
     * Method will return false if language code can't be matched against alias language codes or language settings.
266
     *
267
     * @param \eZ\Publish\SPI\Persistence\Content\URLAlias $spiUrlAlias
268
     * @param string|null $languageCode
269
     * @param bool $showAllTranslations
270
     * @param string[] $prioritizedLanguageList
271
     *
272
     * @return string|bool
273
     */
274
    protected function selectAliasLanguageCode(
275
        SPIURLAlias $spiUrlAlias,
276
        $languageCode,
277
        $showAllTranslations,
278
        $prioritizedLanguageList
279
    ) {
280
        if (isset($languageCode) && !in_array($languageCode, $spiUrlAlias->languageCodes)) {
281
            return false;
282
        }
283
284
        foreach ($prioritizedLanguageList as $languageCode) {
285
            if (in_array($languageCode, $spiUrlAlias->languageCodes)) {
286
                return $languageCode;
287
            }
288
        }
289
290
        if ($spiUrlAlias->alwaysAvailable || $showAllTranslations) {
291
            $lastLevelData = end($spiUrlAlias->pathData);
292
            reset($lastLevelData['translations']);
293
294
            return key($lastLevelData['translations']);
295
        }
296
297
        return false;
298
    }
299
300
    /**
301
     * Returns path extracted from normalized path data returned from persistence, using language settings.
302
     *
303
     * Will return false if path could not be determined.
304
     *
305
     * @param \eZ\Publish\SPI\Persistence\Content\URLAlias $spiUrlAlias
306
     * @param string $languageCode
307
     * @param bool $showAllTranslations
308
     * @param string[] $prioritizedLanguageList
309
     *
310
     * @return string|bool
311
     */
312
    protected function extractPath(
313
        SPIURLAlias $spiUrlAlias,
314
        $languageCode,
315
        $showAllTranslations,
316
        $prioritizedLanguageList
317
    ) {
318
        $pathData = array();
319
        $pathLevels = count($spiUrlAlias->pathData);
320
321
        foreach ($spiUrlAlias->pathData as $level => $levelEntries) {
322
            if ($level === $pathLevels - 1) {
323
                $prioritizedLanguageCode = $this->selectAliasLanguageCode(
324
                    $spiUrlAlias,
325
                    $languageCode,
326
                    $showAllTranslations,
327
                    $prioritizedLanguageList
328
                );
329
            } else {
330
                $prioritizedLanguageCode = $this->choosePrioritizedLanguageCode(
331
                    $levelEntries,
332
                    $showAllTranslations,
333
                    $prioritizedLanguageList
334
                );
335
            }
336
337
            if ($prioritizedLanguageCode === false) {
338
                return false;
339
            }
340
341
            $pathData[$level] = $levelEntries['translations'][$prioritizedLanguageCode];
342
        }
343
344
        return implode('/', $pathData);
345
    }
346
347
    /**
348
     * Returns language code with highest priority.
349
     *
350
     * Will return false if language code could nto be matched with language settings in place.
351
     *
352
     * @param array $entries
353
     * @param bool $showAllTranslations
354
     * @param string[] $prioritizedLanguageList
355
     *
356
     * @return string|bool
357
     */
358
    protected function choosePrioritizedLanguageCode(array $entries, $showAllTranslations, $prioritizedLanguageList)
359
    {
360
        foreach ($prioritizedLanguageList as $prioritizedLanguageCode) {
361
            if (isset($entries['translations'][$prioritizedLanguageCode])) {
362
                return $prioritizedLanguageCode;
363
            }
364
        }
365
366
        if ($entries['always-available'] || $showAllTranslations) {
367
            reset($entries['translations']);
368
369
            return key($entries['translations']);
370
        }
371
372
        return false;
373
    }
374
375
    /**
376
     * Matches path string with normalized path data returned from persistence.
377
     *
378
     * Returns matched path string (possibly case corrected) and array of corresponding language codes or false
379
     * if path could not be matched.
380
     *
381
     * @param \eZ\Publish\SPI\Persistence\Content\URLAlias $spiUrlAlias
382
     * @param string $path
383
     * @param string $languageCode
384
     *
385
     * @return array
386
     */
387
    protected function matchPath(SPIURLAlias $spiUrlAlias, $path, $languageCode)
388
    {
389
        $matchedPathElements = array();
390
        $matchedPathLanguageCodes = array();
391
        $pathElements = explode('/', $path);
392
        $pathLevels = count($spiUrlAlias->pathData);
393
394
        foreach ($pathElements as $level => $pathElement) {
395
            if ($level === $pathLevels - 1) {
396
                $matchedLanguageCode = $this->selectAliasLanguageCode(
397
                    $spiUrlAlias,
398
                    $languageCode,
399
                    $this->settings['showAllTranslations'],
400
                    $this->settings['prioritizedLanguageList']
401
                );
402
            } else {
403
                $matchedLanguageCode = $this->matchLanguageCode($spiUrlAlias->pathData[$level], $pathElement);
404
            }
405
406
            if ($matchedLanguageCode === false) {
407
                return array(false, false);
408
            }
409
410
            $matchedPathLanguageCodes[] = $matchedLanguageCode;
411
            $matchedPathElements[] = $spiUrlAlias->pathData[$level]['translations'][$matchedLanguageCode];
412
        }
413
414
        return array(implode('/', $matchedPathElements), $matchedPathLanguageCodes);
415
    }
416
417
    /**
418
     * @param array $pathElementData
419
     * @param string $pathElement
420
     *
421
     * @return string|bool
422
     */
423
    protected function matchLanguageCode(array $pathElementData, $pathElement)
424
    {
425
        foreach ($this->sortTranslationsByPrioritizedLanguages($pathElementData['translations']) as $translationData) {
426
            if (strtolower($pathElement) === strtolower($translationData['text'])) {
427
                return $translationData['lang'];
428
            }
429
        }
430
431
        return false;
432
    }
433
434
    /**
435
     * Needed when translations for the part of the alias are the same for multiple languages.
436
     * In that case we need to ensure that more prioritized language is chosen.
437
     *
438
     * @param array $translations
439
     *
440
     * @return array
441
     */
442
    private function sortTranslationsByPrioritizedLanguages(array $translations)
443
    {
444
        $sortedTranslations = array();
445
        foreach ($this->settings['prioritizedLanguageList'] as $languageCode) {
446
            if (isset($translations[$languageCode])) {
447
                $sortedTranslations[] = array(
448
                    'lang' => $languageCode,
449
                    'text' => $translations[$languageCode],
450
                );
451
                unset($translations[$languageCode]);
452
            }
453
        }
454
455
        foreach ($translations as $languageCode => $translation) {
456
            $sortedTranslations[] = array(
457
                'lang' => $languageCode,
458
                'text' => $translation,
459
            );
460
        }
461
462
        return $sortedTranslations;
463
    }
464
465
    /**
466
     * Returns true or false depending if URL alias is loadable or not for language settings in place.
467
     *
468
     * @param \eZ\Publish\SPI\Persistence\Content\URLAlias $spiUrlAlias
469
     * @param string|null $languageCode
470
     *
471
     * @return bool
472
     */
473
    protected function isUrlAliasLoadable(
474
        SPIURLAlias $spiUrlAlias,
475
        $languageCode,
476
        $showAllTranslations,
477
        $prioritizedLanguageList
478
    ) {
479
        if (isset($languageCode) && !in_array($languageCode, $spiUrlAlias->languageCodes)) {
480
            return false;
481
        }
482
483
        if ($showAllTranslations) {
484
            return true;
485
        }
486
487
        foreach ($spiUrlAlias->pathData as $levelPathData) {
488
            if ($levelPathData['always-available']) {
489
                continue;
490
            }
491
492
            foreach ($levelPathData['translations'] as $translationLanguageCode => $translation) {
493
                if (in_array($translationLanguageCode, $prioritizedLanguageList)) {
494
                    continue 2;
495
                }
496
            }
497
498
            return false;
499
        }
500
501
        return true;
502
    }
503
504
    /**
505
     * Returns true or false depending if URL alias is loadable or not for language settings in place.
506
     *
507
     * @param array $pathData
508
     * @param array $languageCodes
509
     *
510
     * @return bool
511
     */
512
    protected function isPathLoadable(array $pathData, array $languageCodes)
513
    {
514
        if ($this->settings['showAllTranslations']) {
515
            return true;
516
        }
517
518
        foreach ($pathData as $level => $levelPathData) {
519
            if ($levelPathData['always-available']) {
520
                continue;
521
            }
522
523
            if (in_array($languageCodes[$level], $this->settings['prioritizedLanguageList'])) {
524
                continue;
525
            }
526
527
            return false;
528
        }
529
530
        return true;
531
    }
532
533
    /**
534
     * List global aliases.
535
     *
536
     * @param string $languageCode filters those which are valid for the given language
537
     * @param int $offset
538
     * @param int $limit
539
     *
540
     * @return \eZ\Publish\API\Repository\Values\Content\URLAlias[]
541
     */
542
    public function listGlobalAliases($languageCode = null, $offset = 0, $limit = -1)
543
    {
544
        $urlAliasList = array();
545
        $spiUrlAliasList = $this->urlAliasHandler->listGlobalURLAliases(
546
            $languageCode,
547
            $offset,
548
            $limit
549
        );
550
551
        foreach ($spiUrlAliasList as $spiUrlAlias) {
552
            $path = $this->extractPath(
553
                $spiUrlAlias,
554
                $languageCode,
555
                $this->settings['showAllTranslations'],
556
                $this->settings['prioritizedLanguageList']
557
            );
558
559
            if ($path === false) {
560
                continue;
561
            }
562
563
            $urlAliasList[] = $this->buildUrlAliasDomainObject($spiUrlAlias, $path);
564
        }
565
566
        return $urlAliasList;
567
    }
568
569
    /**
570
     * Removes urls aliases.
571
     *
572
     * This method does not remove autogenerated aliases for locations.
573
     *
574
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if alias list contains
575
     *         autogenerated alias
576
     *
577
     * @param \eZ\Publish\API\Repository\Values\Content\URLAlias[] $aliasList
578
     */
579
    public function removeAliases(array $aliasList)
580
    {
581
        $spiUrlAliasList = array();
582
        foreach ($aliasList as $alias) {
583
            if (!$alias->isCustom) {
584
                throw new InvalidArgumentException(
585
                    '$aliasList',
586
                    'Alias list contains autogenerated alias'
587
                );
588
            }
589
            $spiUrlAliasList[] = $this->buildSPIUrlAlias($alias);
590
        }
591
592
        $this->repository->beginTransaction();
593
        try {
594
            $this->urlAliasHandler->removeURLAliases($spiUrlAliasList);
595
            $this->repository->commit();
596
        } catch (Exception $e) {
597
            $this->repository->rollback();
598
            throw $e;
599
        }
600
    }
601
602
    /**
603
     * Builds persistence domain object.
604
     *
605
     * @param \eZ\Publish\API\Repository\Values\Content\URLAlias $urlAlias
606
     *
607
     * @return \eZ\Publish\SPI\Persistence\Content\URLAlias
608
     */
609
    protected function buildSPIUrlAlias(URLAlias $urlAlias)
610
    {
611
        return new SPIURLAlias(
612
            array(
613
                'id' => $urlAlias->id,
614
                'type' => $urlAlias->type,
615
                'destination' => $urlAlias->destination,
616
                'isCustom' => $urlAlias->isCustom,
617
            )
618
        );
619
    }
620
621
    /**
622
     * looks up the URLAlias for the given url.
623
     *
624
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException if the path does not exist or is not valid for the given language
625
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if the path exceeded maximum depth level
626
     *
627
     * @param string $url
628
     * @param string $languageCode
629
     *
630
     * @return \eZ\Publish\API\Repository\Values\Content\URLAlias
631
     */
632
    public function lookup($url, $languageCode = null)
633
    {
634
        $url = $this->cleanUrl($url);
635
636
        $spiUrlAlias = $this->urlAliasHandler->lookup($url);
637
638
        list($path, $languageCodes) = $this->matchPath($spiUrlAlias, $url, $languageCode);
639
        if ($path === false || !$this->isPathLoadable($spiUrlAlias->pathData, $languageCodes)) {
640
            throw new NotFoundException('URLAlias', $url);
641
        }
642
643
        return $this->buildUrlAliasDomainObject($spiUrlAlias, $path);
644
    }
645
646
    /**
647
     * Returns the URL alias for the given location in the given language.
648
     *
649
     * If $languageCode is null the method returns the url alias in the most prioritized language.
650
     *
651
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException if no url alias exist for the given language
652
     *
653
     * @param \eZ\Publish\API\Repository\Values\Content\Location $location
654
     * @param string $languageCode
655
     * @param null|bool $showAllTranslations
656
     * @param null|string[] $prioritizedLanguageList
657
     *
658
     * @return \eZ\Publish\API\Repository\Values\Content\URLAlias
659
     */
660
    public function reverseLookup(
661
        Location $location,
662
        $languageCode = null,
663
        $showAllTranslations = null,
664
        array $prioritizedLanguageList = null
665
    ) {
666
        if ($showAllTranslations === null) {
667
            $showAllTranslations = $this->settings['showAllTranslations'];
668
        }
669
        if ($prioritizedLanguageList === null) {
670
            $prioritizedLanguageList = $this->settings['prioritizedLanguageList'];
671
        }
672
        $urlAliases = $this->listLocationAliases(
673
            $location,
674
            false,
675
            $languageCode,
676
            $showAllTranslations,
677
            $prioritizedLanguageList
678
        );
679
680
        foreach ($prioritizedLanguageList as $prioritizedLanguageCode) {
681
            foreach ($urlAliases as $urlAlias) {
682
                if (in_array($prioritizedLanguageCode, $urlAlias->languageCodes)) {
683
                    return $urlAlias;
684
                }
685
            }
686
        }
687
688
        foreach ($urlAliases as $urlAlias) {
689
            if ($urlAlias->alwaysAvailable) {
690
                return $urlAlias;
691
            }
692
        }
693
694
        if (!empty($urlAliases) && $showAllTranslations) {
695
            return reset($urlAliases);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The expression reset($urlAliases); of type eZ\Publish\API\Repositor...\Content\URLAlias|false adds false to the return on line 695 which is incompatible with the return type declared by the interface eZ\Publish\API\Repositor...sService::reverseLookup of type eZ\Publish\API\Repository\Values\Content\URLAlias. It seems like you forgot to handle an error condition.
Loading history...
696
        }
697
698
        throw new NotFoundException('URLAlias', $location->id);
699
    }
700
701
    /**
702
     * Loads URL alias by given $id.
703
     *
704
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
705
     *
706
     * @param string $id
707
     *
708
     * @return \eZ\Publish\API\Repository\Values\Content\URLAlias
709
     */
710
    public function load($id)
711
    {
712
        $spiUrlAlias = $this->urlAliasHandler->loadUrlAlias($id);
713
        $path = $this->extractPath(
714
            $spiUrlAlias,
715
            null,
716
            $this->settings['showAllTranslations'],
717
            $this->settings['prioritizedLanguageList']
718
        );
719
720
        if ($path === false) {
721
            throw new NotFoundException('URLAlias', $id);
722
        }
723
724
        return $this->buildUrlAliasDomainObject($spiUrlAlias, $path);
725
    }
726
727
    /**
728
     * @param string $url
729
     *
730
     * @return string
731
     */
732
    protected function cleanUrl($url)
733
    {
734
        return trim($url, '/ ');
735
    }
736
737
    /**
738
     * Builds API UrlAlias object from given SPI UrlAlias object.
739
     *
740
     * @param \eZ\Publish\SPI\Persistence\Content\URLAlias $spiUrlAlias
741
     * @param string|null $path
742
     *
743
     * @return \eZ\Publish\API\Repository\Values\Content\URLAlias
744
     */
745
    protected function buildUrlAliasDomainObject(SPIURLAlias $spiUrlAlias, $path)
746
    {
747
        return new URLAlias(
748
            array(
749
                'id' => $spiUrlAlias->id,
750
                'type' => $spiUrlAlias->type,
751
                'destination' => $spiUrlAlias->destination,
752
                'languageCodes' => $spiUrlAlias->languageCodes,
753
                'alwaysAvailable' => $spiUrlAlias->alwaysAvailable,
754
                'path' => '/' . $path,
755
                'isHistory' => $spiUrlAlias->isHistory,
756
                'isCustom' => $spiUrlAlias->isCustom,
757
                'forward' => $spiUrlAlias->forward,
758
            )
759
        );
760
    }
761
}
762