Completed
Push — 6.13 ( 878d09...f11ecd )
by
unknown
26:52
created

refreshSystemUrlAliasesForLocation()   B

Complexity

Conditions 7
Paths 35

Size

Total Lines 51

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
nc 35
nop 2
dl 0
loc 51
rs 8.1357
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Exceptions\NotFoundException as APINotFoundException;
12
use eZ\Publish\API\Repository\URLAliasService as URLAliasServiceInterface;
13
use eZ\Publish\API\Repository\Repository as RepositoryInterface;
14
use eZ\Publish\API\Repository\Values\Content\Content;
15
use eZ\Publish\SPI\Persistence\Content\UrlAlias\Handler;
16
use eZ\Publish\API\Repository\Values\Content\Location;
17
use eZ\Publish\API\Repository\Values\Content\URLAlias;
18
use eZ\Publish\SPI\Persistence\Content\URLAlias as SPIURLAlias;
19
use eZ\Publish\Core\Base\Exceptions\NotFoundException;
20
use eZ\Publish\Core\Base\Exceptions\InvalidArgumentException;
21
use eZ\Publish\Core\Base\Exceptions\UnauthorizedException;
22
use eZ\Publish\API\Repository\Exceptions\ForbiddenException;
23
use Exception;
24
25
/**
26
 * URLAlias service.
27
 *
28
 * @example Examples/urlalias.php
29
 */
30
class URLAliasService implements URLAliasServiceInterface
31
{
32
    /**
33
     * @var \eZ\Publish\API\Repository\Repository
34
     */
35
    protected $repository;
36
37
    /**
38
     * @var \eZ\Publish\SPI\Persistence\Content\UrlAlias\Handler
39
     */
40
    protected $urlAliasHandler;
41
42
    /**
43
     * @var array
44
     */
45
    protected $settings;
46
47
    /**
48
     * @var \eZ\Publish\Core\Repository\Helper\NameSchemaService
49
     */
50
    protected $nameSchemaService;
51
52
    /**
53
     * Setups service with reference to repository object that created it & corresponding handler.
54
     *
55
     * @param \eZ\Publish\API\Repository\Repository $repository
56
     * @param \eZ\Publish\SPI\Persistence\Content\UrlAlias\Handler $urlAliasHandler
57
     * @param \eZ\Publish\Core\Repository\Helper\NameSchemaService
58
     * @param array $settings
59
     */
60
    public function __construct(
61
        RepositoryInterface $repository,
62
        Handler $urlAliasHandler,
63
        Helper\NameSchemaService $nameSchemaService,
64
        array $settings = []
65
    ) {
66
        $this->repository = $repository;
67
        $this->urlAliasHandler = $urlAliasHandler;
68
        // Union makes sure default settings are ignored if provided in argument
69
        $this->settings = $settings + array(
70
            'showAllTranslations' => false,
71
        );
72
        // Get prioritized languages from language service to not have to call it several times
73
        $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...
74
        $this->nameSchemaService = $nameSchemaService;
75
    }
76
77
    /**
78
     * Create a user chosen $alias pointing to $location in $languageCode.
79
     *
80
     * This method runs URL filters and transformers before storing them.
81
     * Hence the path returned in the URLAlias Value may differ from the given.
82
     * $alwaysAvailable makes the alias available in all languages.
83
     *
84
     * @param \eZ\Publish\API\Repository\Values\Content\Location $location
85
     * @param string $path
86
     * @param bool $forwarding if true a redirect is performed
87
     * @param string $languageCode the languageCode for which this alias is valid
88
     * @param bool $alwaysAvailable
89
     *
90
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if the path already exists for the given language
91
     *
92
     * @return \eZ\Publish\API\Repository\Values\Content\URLAlias
93
     */
94
    public function createUrlAlias(Location $location, $path, $languageCode, $forwarding = false, $alwaysAvailable = false)
95
    {
96
        $path = $this->cleanUrl($path);
97
98
        $this->repository->beginTransaction();
99
        try {
100
            $spiUrlAlias = $this->urlAliasHandler->createCustomUrlAlias(
101
                $location->id,
102
                $path,
103
                $forwarding,
104
                $languageCode,
105
                $alwaysAvailable
106
            );
107
            $this->repository->commit();
108
        } catch (ForbiddenException $e) {
109
            $this->repository->rollback();
110
            throw new InvalidArgumentException(
111
                '$path',
112
                $e->getMessage(),
113
                $e
114
            );
115
        } catch (Exception $e) {
116
            $this->repository->rollback();
117
            throw $e;
118
        }
119
120
        return $this->buildUrlAliasDomainObject($spiUrlAlias, $path);
121
    }
122
123
    /**
124
     * Create a user chosen $alias pointing to a resource in $languageCode.
125
     *
126
     * This method does not handle location resources - if a user enters a location target
127
     * the createCustomUrlAlias method has to be used.
128
     * This method runs URL filters and and transformers before storing them.
129
     * Hence the path returned in the URLAlias Value may differ from the given.
130
     *
131
     * $alwaysAvailable makes the alias available in all languages.
132
     *
133
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if the path already exists for the given
134
     *         language or if resource is not valid
135
     *
136
     * @param string $resource
137
     * @param string $path
138
     * @param string $languageCode
139
     * @param bool $forwarding
140
     * @param bool $alwaysAvailable
141
     *
142
     * @return \eZ\Publish\API\Repository\Values\Content\URLAlias
143
     */
144
    public function createGlobalUrlAlias($resource, $path, $languageCode, $forwarding = false, $alwaysAvailable = false)
145
    {
146
        if (!preg_match('#^([a-zA-Z0-9_]+):(.+)$#', $resource, $matches)) {
147
            throw new InvalidArgumentException('$resource', 'argument is not valid');
148
        }
149
150
        $path = $this->cleanUrl($path);
151
152
        if ($matches[1] === 'eznode' || 0 === strpos($resource, 'module:content/view/full/')) {
153
            if ($matches[1] === 'eznode') {
154
                $locationId = $matches[2];
155
            } else {
156
                $resourcePath = explode('/', $matches[2]);
157
                $locationId = end($resourcePath);
158
            }
159
160
            return $this->createUrlAlias(
161
                $this->repository->getLocationService()->loadLocation($locationId),
162
                $path,
163
                $languageCode,
164
                $forwarding,
165
                $alwaysAvailable
166
            );
167
        }
168
169
        $this->repository->beginTransaction();
170
        try {
171
            $spiUrlAlias = $this->urlAliasHandler->createGlobalUrlAlias(
172
                $matches[1] . ':' . $this->cleanUrl($matches[2]),
173
                $path,
174
                $forwarding,
175
                $languageCode,
176
                $alwaysAvailable
177
            );
178
            $this->repository->commit();
179
        } catch (ForbiddenException $e) {
180
            $this->repository->rollback();
181
            throw new InvalidArgumentException('$path', $e->getMessage(), $e);
182
        } catch (Exception $e) {
183
            $this->repository->rollback();
184
            throw $e;
185
        }
186
187
        return $this->buildUrlAliasDomainObject($spiUrlAlias, $path);
188
    }
189
190
    /**
191
     * List of url aliases pointing to $location, sorted by language priority.
192
     *
193
     * @param \eZ\Publish\API\Repository\Values\Content\Location $location
194
     * @param bool $custom if true the user generated aliases are listed otherwise the autogenerated
195
     * @param string $languageCode filters those which are valid for the given language
196
     * @param null|bool $showAllTranslations
197
     * @param null|string[] $prioritizedLanguageList
198
     *
199
     * @return \eZ\Publish\API\Repository\Values\Content\URLAlias[]
200
     */
201
    public function listLocationAliases(
202
        Location $location,
203
        $custom = true,
204
        $languageCode = null,
205
        $showAllTranslations = null,
206
        array $prioritizedLanguageList = null
207
    ) {
208
        $spiUrlAliasList = $this->urlAliasHandler->listURLAliasesForLocation(
209
            $location->id,
210
            $custom
211
        );
212
        if ($showAllTranslations === null) {
213
            $showAllTranslations = $this->settings['showAllTranslations'];
214
        }
215
        if ($prioritizedLanguageList === null) {
216
            $prioritizedLanguageList = $this->settings['prioritizedLanguageList'];
217
        }
218
        $urlAliasList = array();
219
220
        foreach ($spiUrlAliasList as $spiUrlAlias) {
221
            if (
222
                !$this->isUrlAliasLoadable(
223
                    $spiUrlAlias,
224
                    $languageCode,
225
                    $showAllTranslations,
226
                    $prioritizedLanguageList
227
                )
228
            ) {
229
                continue;
230
            }
231
232
            $path = $this->extractPath(
233
                $spiUrlAlias,
234
                $languageCode,
235
                $showAllTranslations,
236
                $prioritizedLanguageList
237
            );
238
239
            if ($path === false) {
240
                continue;
241
            }
242
243
            $urlAliasList[$spiUrlAlias->id] = $this->buildUrlAliasDomainObject($spiUrlAlias, $path);
244
        }
245
246
        $prioritizedAliasList = array();
247
        foreach ($prioritizedLanguageList as $languageCode) {
248
            foreach ($urlAliasList as $urlAlias) {
249
                foreach ($urlAlias->languageCodes as $aliasLanguageCode) {
250
                    if ($aliasLanguageCode === $languageCode) {
251
                        $prioritizedAliasList[$urlAlias->id] = $urlAlias;
252
                        break;
253
                    }
254
                }
255
            }
256
        }
257
258
        // Add aliases not matched by prioritized language to the end of the list
259
        return array_values($prioritizedAliasList + $urlAliasList);
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
     * Refresh all system URL aliases for the given Location (and historize outdated if needed).
729
     *
730
     * @param \eZ\Publish\API\Repository\Values\Content\Location $location
731
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
732
     *
733
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
734
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
735
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
736
     * @throws \Exception any unexpected exception that might come from custom Field Type implementation
737
     */
738
    public function refreshSystemUrlAliasesForLocation(Location $location, Content $content = null)
739
    {
740
        if (!$this->repository->getPermissionResolver()->canUser('content', 'urltranslator', $location)) {
741
            throw new UnauthorizedException('content', 'urltranslator');
742
        }
743
744
        $this->repository->beginTransaction();
745
        try {
746
            if ($content === null) {
747
                $content = $this->repository->getContentService()->loadContent(
748
                    $location->contentInfo->id
749
                );
750
            } else {
751
                // perform sanity check
752
                if ($location->contentId !== $content->id) {
753
                    throw new InvalidArgumentException(
754
                        '$content',
755
                        sprintf(
756
                            'Location %d expects Content %d but got %d',
757
                            $location->id,
758
                            $location->contentId,
759
                            $content->id
760
                        )
761
                    );
762
                }
763
            }
764
            $urlAliasNames = $this->nameSchemaService->resolveUrlAliasSchema($content);
765
            foreach ($urlAliasNames as $languageCode => $name) {
766
                $this->urlAliasHandler->publishUrlAliasForLocation(
767
                    $location->id,
768
                    $location->parentLocationId,
769
                    $name,
770
                    $languageCode,
771
                    $content->contentInfo->alwaysAvailable
772
                );
773
            }
774
            // handle URL aliases for missing Translations
775
            $this->urlAliasHandler->archiveUrlAliasesForDeletedTranslations(
776
                $location->id,
777
                $location->parentLocationId,
778
                $content->getVersionInfo()->languageCodes
779
            );
780
            $this->repository->commit();
781
        } catch (APINotFoundException $e) {
782
            $this->repository->rollback();
783
            throw $e;
784
        } catch (Exception $e) {
785
            $this->repository->rollback();
786
            throw $e;
787
        }
788
    }
789
790
    /**
791
     * Delete global, system or custom URL alias pointing to non-existent Locations.
792
     *
793
     * @return int Number of removed URL aliases
794
     *
795
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
796
     */
797
    public function deleteCorruptedUrlAliases()
798
    {
799
        if ($this->repository->getPermissionResolver()->hasAccess('content', 'urltranslator') !== true) {
800
            throw new UnauthorizedException('content', 'urltranslator');
801
        }
802
803
        return $this->urlAliasHandler->deleteCorruptedUrlAliases();
804
    }
805
806
    /**
807
     * @param string $url
808
     *
809
     * @return string
810
     */
811
    protected function cleanUrl($url)
812
    {
813
        return trim($url, '/ ');
814
    }
815
816
    /**
817
     * Builds API UrlAlias object from given SPI UrlAlias object.
818
     *
819
     * @param \eZ\Publish\SPI\Persistence\Content\URLAlias $spiUrlAlias
820
     * @param string|null $path
821
     *
822
     * @return \eZ\Publish\API\Repository\Values\Content\URLAlias
823
     */
824
    protected function buildUrlAliasDomainObject(SPIURLAlias $spiUrlAlias, $path)
825
    {
826
        return new URLAlias(
827
            array(
828
                'id' => $spiUrlAlias->id,
829
                'type' => $spiUrlAlias->type,
830
                'destination' => $spiUrlAlias->destination,
831
                'languageCodes' => $spiUrlAlias->languageCodes,
832
                'alwaysAvailable' => $spiUrlAlias->alwaysAvailable,
833
                'path' => '/' . $path,
834
                'isHistory' => $spiUrlAlias->isHistory,
835
                'isCustom' => $spiUrlAlias->isCustom,
836
                'forward' => $spiUrlAlias->forward,
837
            )
838
        );
839
    }
840
}
841