5bf892fff2cc61a39c689048cbab94793c83de47
[yaffs-website] / vendor / drush / drush / src / SiteAlias / SiteSpecParser.php
1 <?php
2 namespace Drush\SiteAlias;
3
4 /**
5  * Parse a string that contains a site specification.
6  *
7  * Site specifications contain some of the following elements:
8  *   - user
9  *   - host
10  *   - path
11  *   - uri (multisite selector)
12  */
13 class SiteSpecParser
14 {
15     /**
16      * Parse a site specification
17      *
18      * @param string $spec
19      *   A site specification in one of the accepted forms:
20      *     - /path/to/drupal#uri
21      *     - user@server/path/to/drupal#uri
22      *     - user@server/path/to/drupal
23      *     - user@server#uri
24      *   or, a site name:
25      *     - #uri
26      * @param string $root
27      *   Drupal root (if provided).
28      * @return array
29      *   A site specification array with the specified components filled in:
30      *     - user
31      *     - host
32      *     - path
33      *     - uri
34      *   or, an empty array if the provided parameter is not a valid site spec.
35      */
36     public function parse($spec, $root = '')
37     {
38         $result = $this->match($spec);
39         return $this->fixAndCheckUsability($result, $root);
40     }
41
42     /**
43      * Determine if the provided specification is valid. Note that this
44      * tests only for syntactic validity; to see if the specification is
45      * usable, call 'parse()', which will also filter out specifications
46      * for local sites that specify a multidev site that does not exist.
47      *
48      * @param string $spec
49      *   @see parse()
50      * @return bool
51      */
52     public function validSiteSpec($spec)
53     {
54         $result = $this->match($spec);
55         return !empty($result);
56     }
57
58     /**
59      * Determine whether or not the provided name is an alias name.
60      *
61      * @param string $aliasName
62      * @return bool
63      */
64     public function isAliasName($aliasName)
65     {
66         return !empty($aliasName) && ($aliasName[0] == '@');
67     }
68
69     /**
70      * Return the set of regular expression patterns that match the available
71      * site specification formats.
72      *
73      * @return array
74      *   key: site specification regex
75      *   value: an array mapping from site specification component names to
76      *     the elements in the 'matches' array containing the data for that element.
77      */
78     protected function patterns()
79     {
80         return [
81             // /path/to/drupal#uri
82             '%^(/[^#]*)#([a-zA-Z0-9_-]+)$%' => [
83                 'root' => 1,
84                 'uri' => 2,
85             ],
86             // user@server/path/to/drupal#uri
87             '%^([a-zA-Z0-9_-]+)@([a-zA-Z0-9_-]+)(/[^#]*)#([a-zA-Z0-9_-]+)$%' => [
88                 'user' => 1,
89                 'host' => 2,
90                 'root' => 3,
91                 'uri' => 4,
92             ],
93             // user@server/path/to/drupal
94             '%^([a-zA-Z0-9_-]+)@([a-zA-Z0-9_-]+)(/[^#]*)$%' => [
95                 'user' => 1,
96                 'host' => 2,
97                 'root' => 3,
98                 'uri' => 'default', // Or '2' if uri should be 'host'
99             ],
100             // user@server#uri
101             '%^([a-zA-Z0-9_-]+)@([a-zA-Z0-9_-]+)#([a-zA-Z0-9_-]+)$%' => [
102                 'user' => 1,
103                 'host' => 2,
104                 'uri' => 3,
105             ],
106             // #uri
107             '%^#([a-zA-Z0-9_-]+)$%' => [
108                 'uri' => 1,
109             ],
110         ];
111     }
112
113     /**
114      * Run through all of the available regex patterns and determine if
115      * any match the provided specification.
116      *
117      * @return array
118      *   @see parse()
119      */
120     protected function match($spec)
121     {
122         foreach ($this->patterns() as $regex => $map) {
123             if (preg_match($regex, $spec, $matches)) {
124                 return $this->mapResult($map, $matches);
125             }
126         }
127         return [];
128     }
129
130     /**
131      * Inflate the provided array so that it always contains the required
132      * elements.
133      *
134      * @return array
135      *   @see parse()
136      */
137     protected function defaults($result = [])
138     {
139         $result += [
140             'root' => '',
141             'uri' => '',
142         ];
143
144         return $result;
145     }
146
147     /**
148      * Take the data from the matches from the regular expression and
149      * plug them into the result array per the info in the provided map.
150      *
151      * @param array $map
152      *   An array mapping from result key to matches index.
153      * @param array $matches
154      *   The matched strings returned from preg_match
155      * @return array
156      *   @see parse()
157      */
158     protected function mapResult($map, $matches)
159     {
160         $result = [];
161
162         foreach ($map as $key => $index) {
163             $value = is_string($index) ? $index : $matches[$index];
164             $result[$key] = $value;
165         }
166
167         if (empty($result)) {
168             return [];
169         }
170
171         return $this->defaults($result);
172     }
173
174     /**
175      * Validate the provided result. If the result is local, then it must
176      * have a 'root'. If it does not, then fill in the root that was provided
177      * to us in our consturctor.
178      *
179      * @param array $result
180      *   @see parse() result.
181      * @return array
182      *   @see parse()
183      */
184     protected function fixAndCheckUsability($result, $root)
185     {
186         if (empty($result) || !empty($result['host'])) {
187             return $result;
188         }
189
190         if (empty($result['root'])) {
191             // TODO: should these throw an exception, so the user knows
192             // why their site spec was invalid?
193             if (empty($root) || !is_dir($root)) {
194                 return [];
195             }
196
197             $result['root'] = $root;
198         }
199
200         // TODO: If using a sitespec `#uri`, then `uri` MUST
201         // be the name of a folder that exists in __DRUPAL_ROOT__/sites.
202         // This restriction does NOT apply to the --uri option. Are there
203         // instances where we need to allow 'uri' to be a literal uri
204         // rather than the folder name? If so, we need to loosen this check.
205         // I think it's fine as it is, though.
206         $path = $result['root'] . '/sites/' . $result['uri'];
207         if (!is_dir($path)) {
208             return [];
209         }
210
211         return $result;
212     }
213 }