Updated to Drupal 8.5. Core Media not yet in use.
[yaffs-website] / vendor / drush / drush / src / SiteAlias / HostPath.php
1 <?php
2 namespace Drush\SiteAlias;
3
4 use Consolidation\Config\Config;
5 use Consolidation\Config\ConfigInterface;
6 use Webmozart\PathUtil\Path;
7
8 /**
9  * A host path is a path on some machine. The machine may be specified
10  * by a label, and the label may be an @alias or a site specification.
11  * If there is no label, then the local machine is assumed.
12  *
13  * Examples:
14  *
15  *   @alias
16  *   @alias:/path
17  *   host:/path
18  *   user@host:/path
19  *   user@host/drupal-root#uri:/path
20  *   /path
21  *
22  * Note that /path does not have to begin with a '/'; it may
23  * be a relative path, or it may begin with a path alias,
24  * e.g. '%files'.
25  *
26  * It is permissible to have an alias or site specification
27  * without a path, but it is not valid to have just a host
28  * with no path.
29  */
30 class HostPath
31 {
32     /** @var AliasRecord The alias record obtained from the host path */
33     protected $alias_record;
34
35     /** @var string The entire original host path (e.g. @alias:/path) */
36     protected $original_path;
37
38     /** @var string The "path" component from the host path */
39     protected $path;
40
41     /** @var string The alias record is implicit (e.g. 'path' instead of '@self:path') */
42     protected $implicit;
43
44     /**
45      * HostPath constructor
46      *
47      * @param AliasRecord $alias_record The alias record or site specification record
48      * @param string $original_path The original host path
49      * @param string $path Just the 'path' component
50      */
51     protected function __construct($alias_record, $original_path, $path = '', $implicit = false)
52     {
53         $this->alias_record = $alias_record;
54         $this->original_path = $original_path;
55         $this->path = $path;
56         $this->implicit = $implicit;
57     }
58
59     /**
60      * Factory method to create a host path.
61      *
62      * @param SiteAliasManager $manager We need to be provided a reference
63      *   to the alias manager to create a host path
64      * @param string $hostPath The path to create.
65      */
66     public static function create(SiteAliasManager $manager, $hostPath)
67     {
68         // Split the alias path up into
69         //  - $parts[0]: everything before the first ":"
70         //  - $parts[1]: everything after the ":", if there was one.
71         $parts = explode(':', $hostPath, 2);
72
73         // Determine whether or not $parts[0] is a site spec or an alias
74         // record.  If $parts[0] is not in the right form, the result
75         // will be 'false'. This will throw if $parts[0] is an @alias
76         // record, but the requested alias cannot be found.
77         $alias_record = $manager->get($parts[0]);
78
79         if (!isset($parts[1])) {
80             return static::determinePathOrAlias($manager, $alias_record, $hostPath, $parts[0]);
81         }
82
83         // If $parts[0] did not resolve to a site spec or alias record,
84         // but there is a $parts[1], then $parts[0] must be a machine name.
85         // Unless it was an alias that could not be found.
86         if ($alias_record === false) {
87             if (SiteAliasName::isAliasName($parts[0])) {
88                 throw new \Exception('Site alias ' . $parts[0] . ' not found.');
89             }
90             $alias_record = new AliasRecord(['host' => $parts[0]]);
91         }
92
93         // Create our alias path
94         return new HostPath($alias_record, $hostPath, $parts[1]);
95     }
96
97     /**
98      * Return the alias record portion of the host path.
99      *
100      * @return AliasRecord
101      */
102     public function getAliasRecord()
103     {
104         return $this->alias_record;
105     }
106
107     /**
108      * Returns true if this host path points at a remote machine
109      *
110      * @return bool
111      */
112     public function isRemote()
113     {
114         return $this->alias_record->isRemote();
115     }
116
117     /**
118      * Return the original host path string, as provided to the create() method.
119      *
120      * @return string
121      */
122     public function getOriginal()
123     {
124         return $this->original_path;
125     }
126
127     /**
128      * Return just the path portion, without considering the alias root.
129      *
130      * @return string
131      */
132     public function getOriginalPath()
133     {
134         return $this->path;
135     }
136
137     /**
138      * Return the original path
139      *
140      * @return string
141      */
142     public function getPath()
143     {
144         if (empty($this->path)) {
145             return $this->alias_record->root();
146         }
147         if ($this->alias_record->hasRoot() && !$this->implicit) {
148             return Path::makeAbsolute($this->path, $this->alias_record->root());
149         }
150         return $this->path;
151     }
152
153     /**
154      * Returns 'true' if the path portion of the host path begins with a
155      * path alias (e.g. '%files'). Path aliases must appear at the beginning
156      * of the path.
157      *
158      * @return bool
159      */
160     public function hasPathAlias()
161     {
162         $pathAlias = $this->getPathAlias();
163         return !empty($pathAlias);
164     }
165
166     /**
167      * Return just the path alias portion of the path (e.g. '%files'), or
168      * empty if there is no alias in the path.
169      *
170      * @return string
171      */
172     public function getPathAlias()
173     {
174         if (preg_match('#%([^/]*).*#', $this->path, $matches)) {
175             return $matches[1];
176         }
177         return '';
178     }
179
180     /**
181      * Replaces the path alias portion of the path with the resolved path.
182      *
183      * @param string $resolvedPath The converted path alias (e.g. 'sites/default/files')
184      * @return $this
185      */
186     public function replacePathAlias($resolvedPath)
187     {
188         $pathAlias = $this->getPathAlias();
189         if (empty($pathAlias)) {
190             return $this;
191         }
192         // Make sure that the resolved path always ends in a '\'.
193         $resolvedPath .= '/';
194         // Avoid double / in path.
195         //   $this->path: %files/foo
196         //   $pathAlias:   files
197         // We add one to the length of $pathAlias to account for the '%' in $this->path.
198         if (strlen($this->path) > (strlen($pathAlias) + 1)) {
199             $resolvedPath = rtrim($resolvedPath, '/');
200         }
201         // Once the path alias is resolved, replace the alias in the $path with the result.
202         $this->path = $resolvedPath . substr($this->path, strlen($pathAlias) + 1);
203
204         // Using a path alias such as %files is equivalent to making explicit
205         // use of @self:%files. We set implicit to false here so that the resolved
206         // path will be returned as an absolute path rather than a relative path.
207         $this->implicit = false;
208
209         return $this;
210     }
211
212     /**
213      * Return the host portion of the host path, including the user.
214      *
215      * @return string
216      */
217     public function getHost()
218     {
219         return $this->alias_record->remoteHostWithUser();
220     }
221
222     /**
223      * Return the fully resolved path, e.g. user@server:/path/to/drupalroot/sites/default/files
224      *
225      * @return string
226      */
227     public function fullyQualifiedPath()
228     {
229         $host = $this->getHost();
230         if (!empty($host)) {
231             return $host . ':' . $this->getPath();
232         }
233         return $this->getPath();
234     }
235
236     /**
237      * Our fully qualified path passes the result through Path::makeAbsolute()
238      * which canonicalizes the path, removing any trailing slashes.
239      * That is what we want most of the time; however, the trailing slash is
240      * sometimes significant, e.g. for rsync, so we provide a separate API
241      * for those cases where the trailing slash should be preserved.
242      *
243      * @return string
244      */
245     public function fullyQualifiedPathPreservingTrailingSlash()
246     {
247         $fqp = $this->fullyQualifiedPath();
248         if ((substr($this->path, strlen($this->path) - 1) == '/') && (substr($fqp, strlen($fqp) - 1) != '/')) {
249             $fqp .= '/';
250         }
251         return $fqp;
252     }
253
254     /**
255      * Helper method for HostPath::create(). When the host path contains no
256      * ':', this method determines whether the string that was provided is
257      * a host or a path.
258      *
259      * @param SiteAliasManager $manager
260      * @param AliasRecord|bool $alias_record
261      * @param string $hostPath
262      * @param string $single_part
263      */
264     protected static function determinePathOrAlias(SiteAliasManager $manager, $alias_record, $hostPath, $single_part)
265     {
266         // If $alias_record is false, then $single_part must be a path.
267         if ($alias_record === false) {
268             return new HostPath($manager->getSelf(), $hostPath, $single_part, true);
269         }
270
271         // Otherwise, we have a alias record without a path.
272         // In this instance, the alias record _must_ have a root.
273         if (!$alias_record->hasRoot()) {
274             throw new \Exception("$hostPath does not define a path.");
275         }
276         return new HostPath($alias_record, $hostPath);
277     }
278 }