v1/vendor/consolidation/site-alias/src/SiteSpecParser.php

239 lines
6.6 KiB
PHP

<?php
namespace Consolidation\SiteAlias;
/**
* Parse a string that contains a site specification.
*
* Site specifications contain some of the following elements:
* - user
* - host
* - path
* - uri (multisite selector)
*/
class SiteSpecParser
{
/**
* @var string Relative path from the site root to directory where
* multisite configuration directories are found.
*/
protected $multisiteDirectoryRoot = 'sites';
/**
* Parse a site specification
*
* @param string $spec
* A site specification in one of the accepted forms:
* - /path/to/drupal#uri
* - user@server/path/to/drupal#uri
* - user@server/path/to/drupal
* - user@server#uri
* or, a site name:
* - #uri
* @param string $root
* Drupal root (if provided).
* @return array
* A site specification array with the specified components filled in:
* - user
* - host
* - path
* - uri
* or, an empty array if the provided parameter is not a valid site spec.
*/
public function parse($spec, $root = '')
{
$result = $this->match($spec);
return $this->fixAndCheckUsability($result, $root);
}
/**
* Determine if the provided specification is valid. Note that this
* tests only for syntactic validity; to see if the specification is
* usable, call 'parse()', which will also filter out specifications
* for local sites that specify a multidev site that does not exist.
*
* @param string $spec
* @see parse()
* @return bool
*/
public function validSiteSpec($spec)
{
$result = $this->match($spec);
return !empty($result);
}
/**
* Determine whether or not the provided name is an alias name.
*
* @param string $aliasName
* @return bool
*/
public function isAliasName($aliasName)
{
return !empty($aliasName) && ($aliasName[0] == '@');
}
public function setMultisiteDirectoryRoot($location)
{
$this->multisiteDirectoryRoot = $location;
}
public function getMultisiteDirectoryRoot($root)
{
return $root . DIRECTORY_SEPARATOR . $this->multisiteDirectoryRoot;
}
/**
* Return the set of regular expression patterns that match the available
* site specification formats.
*
* @return array
* key: site specification regex
* value: an array mapping from site specification component names to
* the elements in the 'matches' array containing the data for that element.
*/
protected function patterns()
{
$PATH = '([a-zA-Z]:[/\\\\][^#]*|[/\\\\][^#]*)';
$USER = '([a-zA-Z0-9\._-]+)';
$SERVER = '([a-zA-Z0-9\._-]+)';
$URI = '([a-zA-Z0-9_-]+)';
return [
// /path/to/drupal#uri
"%^{$PATH}#{$URI}\$%" => [
'root' => 1,
'uri' => 2,
],
// user@server/path/to/drupal#uri
"%^{$USER}@{$SERVER}{$PATH}#{$URI}\$%" => [
'user' => 1,
'host' => 2,
'root' => 3,
'uri' => 4,
],
// user@server/path/to/drupal
"%^{$USER}@{$SERVER}{$PATH}\$%" => [
'user' => 1,
'host' => 2,
'root' => 3,
'uri' => 'default', // Or '2' if uri should be 'host'
],
// user@server#uri
"%^{$USER}@{$SERVER}#{$URI}\$%" => [
'user' => 1,
'host' => 2,
'uri' => 3,
],
// #uri
"%^#{$URI}\$%" => [
'uri' => 1,
],
];
}
/**
* Run through all of the available regex patterns and determine if
* any match the provided specification.
*
* @return array
* @see parse()
*/
protected function match($spec)
{
if ($spec === null) {
$spec = '';
}
foreach ($this->patterns() as $regex => $map) {
if (preg_match($regex, $spec, $matches)) {
return $this->mapResult($map, $matches);
}
}
return [];
}
/**
* Inflate the provided array so that it always contains the required
* elements.
*
* @return array
* @see parse()
*/
protected function defaults($result = [])
{
$result += [
'root' => '',
'uri' => '',
];
return $result;
}
/**
* Take the data from the matches from the regular expression and
* plug them into the result array per the info in the provided map.
*
* @param array $map
* An array mapping from result key to matches index.
* @param array $matches
* The matched strings returned from preg_match
* @return array
* @see parse()
*/
protected function mapResult($map, $matches)
{
$result = [];
foreach ($map as $key => $index) {
$value = is_string($index) ? $index : $matches[$index];
$result[$key] = $value;
}
if (empty($result)) {
return [];
}
return $this->defaults($result);
}
/**
* Validate the provided result. If the result is local, then it must
* have a 'root'. If it does not, then fill in the root that was provided
* to us in our consturctor.
*
* @param array $result
* @see parse() result.
* @return array
* @see parse()
*/
protected function fixAndCheckUsability($result, $root)
{
if (empty($result) || !empty($result['host'])) {
return $result;
}
if (empty($result['root'])) {
// TODO: should these throw an exception, so the user knows
// why their site spec was invalid?
if (empty($root) || !is_dir($root)) {
return [];
}
$result['root'] = $root;
}
// If using a sitespec `#uri`, then `uri` MUST
// be the name of a folder that exists in __DRUPAL_ROOT__/sites.
// This restriction does NOT apply to the --uri option. Are there
// instances where we need to allow 'uri' to be a literal uri
// rather than the folder name? If so, we need to loosen this check.
// I think it's fine as it is, though.
$path = $this->getMultisiteDirectoryRoot($result['root']) . DIRECTORY_SEPARATOR . $result['uri'];
if (!is_dir($path)) {
return [];
}
return $result;
}
}