43fc5fa3fd25bf38162b4e63c415545c1937a3b6
[yaffs-website] / web / modules / contrib / pathauto / src / AliasUniquifier.php
1 <?php
2
3 namespace Drupal\pathauto;
4
5 use Drupal\Component\Utility\Unicode;
6 use Drupal\Core\Config\ConfigFactoryInterface;
7 use Drupal\Core\Extension\ModuleHandlerInterface;
8 use Drupal\Core\Language\LanguageInterface;
9 use Drupal\Core\Path\AliasManagerInterface;
10 use Drupal\Core\Routing\RouteProviderInterface;
11
12 /**
13  * Provides a utility for creating a unique path alias.
14  */
15 class AliasUniquifier implements AliasUniquifierInterface {
16
17   /**
18    * Config factory.
19    *
20    * @var \Drupal\Core\Config\ConfigFactoryInterface
21    */
22   protected $configFactory;
23
24   /**
25    * The alias storage helper.
26    *
27    * @var \Drupal\pathauto\AliasStorageHelperInterface
28    */
29   protected $aliasStorageHelper;
30
31   /**
32    * The module handler.
33    *
34    * @var \Drupal\Core\Extension\ModuleHandlerInterface
35    */
36   protected $moduleHandler;
37
38   /**
39    * The route provider service.
40    *
41    * @var \Drupal\Core\Routing\RouteProviderInterface.
42    */
43   protected $routeProvider;
44
45   /**
46    * The alias manager.
47    *
48    * @var \Drupal\Core\Path\AliasManagerInterface
49    */
50   protected $aliasManager;
51
52   /**
53    * Creates a new AliasUniquifier.
54    *
55    * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
56    *   The config factory.
57    * @param \Drupal\pathauto\AliasStorageHelperInterface $alias_storage_helper
58    *   The alias storage helper.
59    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
60    *   The module handler.
61    * @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
62    *   The route provider service.
63    */
64   public function __construct(ConfigFactoryInterface $config_factory, AliasStorageHelperInterface $alias_storage_helper, ModuleHandlerInterface $module_handler, RouteProviderInterface $route_provider, AliasManagerInterface $alias_manager) {
65     $this->configFactory = $config_factory;
66     $this->aliasStorageHelper = $alias_storage_helper;
67     $this->moduleHandler = $module_handler;
68     $this->routeProvider = $route_provider;
69     $this->aliasManager = $alias_manager;
70   }
71
72   /**
73    * {@inheritdoc}
74    */
75   public function uniquify(&$alias, $source, $langcode) {
76     $config = $this->configFactory->get('pathauto.settings');
77
78     if (!$this->isReserved($alias, $source, $langcode)) {
79       return;
80     }
81
82     // If the alias already exists, generate a new, hopefully unique, variant.
83     $maxlength = min($config->get('max_length'), $this->aliasStorageHelper->getAliasSchemaMaxlength());
84     $separator = $config->get('separator');
85     $original_alias = $alias;
86
87     $i = 0;
88     do {
89       // Append an incrementing numeric suffix until we find a unique alias.
90       $unique_suffix = $separator . $i;
91       $alias = Unicode::truncate($original_alias, $maxlength - Unicode::strlen($unique_suffix), TRUE) . $unique_suffix;
92       $i++;
93     } while ($this->isReserved($alias, $source, $langcode));
94   }
95
96   /**
97    * {@inheritdoc}
98    */
99   public function isReserved($alias, $source, $langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED) {
100     // Check if this alias already exists.
101     if ($existing_source = $this->aliasManager->getPathByAlias($alias, $langcode)) {
102       if ($existing_source != $alias) {
103         // If it is an alias for the provided source, it is allowed to keep using
104         // it. If not, then it is reserved.
105         return $existing_source != $source;
106       }
107
108     }
109
110     // Then check if there is a route with the same path.
111     if ($this->isRoute($alias)) {
112       return TRUE;
113     }
114     // Finally check if any other modules have reserved the alias.
115     $args = array(
116       $alias,
117       $source,
118       $langcode,
119     );
120     $implementations = $this->moduleHandler->getImplementations('pathauto_is_alias_reserved');
121     foreach ($implementations as $module) {
122
123       $result = $this->moduleHandler->invoke($module, 'pathauto_is_alias_reserved', $args);
124
125       if (!empty($result)) {
126         // As soon as the first module says that an alias is in fact reserved,
127         // then there is no point in checking the rest of the modules.
128         return TRUE;
129       }
130     }
131
132     return FALSE;
133   }
134
135   /**
136    * Verify if the given path is a valid route.
137    *
138    * @param string $path
139    *   A string containing a relative path.
140    *
141    * @return bool
142    *   TRUE if the path already exists.
143    *
144    * @throws \InvalidArgumentException
145    */
146   public function isRoute($path) {
147     if (is_file(DRUPAL_ROOT . '/' . $path) || is_dir(DRUPAL_ROOT . '/' . $path)) {
148       // Do not allow existing files or directories to get assigned an automatic
149       // alias. Note that we do not need to use is_link() to check for symbolic
150       // links since this returns TRUE for either is_file() or is_dir() already.
151       return TRUE;
152     }
153
154     $routes = $this->routeProvider->getRoutesByPattern($path);
155
156     // Only return true for an exact match, ignore placeholders.
157     foreach ($routes as $route) {
158       if ($route->getPath() == $path) {
159         return TRUE;
160       }
161     }
162
163     return FALSE;
164
165   }
166
167 }