media-cloud-sync
/
includes
/
sdk
/
google
/
rize
/
uri-template
/
src
/
Rize
/
UriTemplate
/
Parser.php
Parser.php in Media Cloud Sync 1.4.2, at includes/sdk/google/rize/uri-template/src/Rize/UriTemplate/Parser.php
| 1 | <?php |
| 2 | |
| 3 | namespace Dudlewebs\WPMCS\GCP\Rize\UriTemplate; |
| 4 | |
| 5 | use Dudlewebs\WPMCS\GCP\Rize\UriTemplate\Node\Abstraction; |
| 6 | use Dudlewebs\WPMCS\GCP\Rize\UriTemplate\Node\Expression; |
| 7 | use Dudlewebs\WPMCS\GCP\Rize\UriTemplate\Node\Variable; |
| 8 | use Dudlewebs\WPMCS\GCP\Rize\UriTemplate\Operator\UnNamed; |
| 9 | class Parser |
| 10 | { |
| 11 | private const REGEX_VARNAME = '[A-z0-9.]|%[0-9a-fA-F]{2}'; |
| 12 | /** |
| 13 | * Parses URI Template and returns nodes. |
| 14 | * |
| 15 | * @return Node\Abstraction[] |
| 16 | */ |
| 17 | public function parse(string $template) : array |
| 18 | { |
| 19 | $parts = \preg_split('#(\\{[^}]+})#', $template, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY); |
| 20 | $nodes = []; |
| 21 | foreach ($parts as $part) { |
| 22 | $node = $this->createNode($part); |
| 23 | // if current node has dot separator that requires a forward lookup |
| 24 | // for the previous node iff previous node's operator is UnNamed |
| 25 | if ($node instanceof Expression && $node->getOperator()->id === '.') { |
| 26 | if (\count($nodes) > 0) { |
| 27 | $previousNode = $nodes[\count($nodes) - 1]; |
| 28 | if ($previousNode instanceof Expression && $previousNode->getOperator() instanceof UnNamed) { |
| 29 | $previousNode->setForwardLookupSeparator($node->getOperator()->id); |
| 30 | } |
| 31 | } |
| 32 | } |
| 33 | $nodes[] = $node; |
| 34 | } |
| 35 | return $nodes; |
| 36 | } |
| 37 | protected function createNode(string $token) : Abstraction |
| 38 | { |
| 39 | // literal string |
| 40 | if ($token[0] !== '{') { |
| 41 | $node = $this->createLiteralNode($token); |
| 42 | } else { |
| 43 | // remove `{}` from expression and parse it |
| 44 | $node = $this->parseExpression(\substr($token, 1, -1)); |
| 45 | } |
| 46 | return $node; |
| 47 | } |
| 48 | protected function parseExpression(string $expression) : Expression |
| 49 | { |
| 50 | $token = $expression; |
| 51 | $prefix = $token[0]; |
| 52 | // not a valid operator? |
| 53 | if (!Operator\Abstraction::isValid($prefix)) { |
| 54 | // not valid chars? |
| 55 | if (!\preg_match('#' . self::REGEX_VARNAME . '#', $token)) { |
| 56 | throw new \InvalidArgumentException("Invalid operator [{$prefix}] found at {$token}"); |
| 57 | } |
| 58 | // default operator |
| 59 | // |
| 60 | // PHP 8.5: using null as array offset is deprecated and we no longer rely on auto-casting null to ''. |
| 61 | $prefix = ''; |
| 62 | } |
| 63 | // remove operator prefix if exists e.g. '?' |
| 64 | if ($prefix) { |
| 65 | $token = \substr($token, 1); |
| 66 | } |
| 67 | // parse variables |
| 68 | $vars = []; |
| 69 | foreach (\explode(',', $token) as $var) { |
| 70 | $vars[] = $this->parseVariable($var); |
| 71 | } |
| 72 | return $this->createExpressionNode($token, $this->createOperatorNode($prefix), $vars); |
| 73 | } |
| 74 | protected function parseVariable(string $var) : Variable |
| 75 | { |
| 76 | $var = \trim($var); |
| 77 | $val = null; |
| 78 | $modifier = null; |
| 79 | // check for prefix (:) / explode (*) / array (%) modifier |
| 80 | if (\str_contains($var, ':')) { |
| 81 | $modifier = ':'; |
| 82 | [$varname, $val] = \explode(':', $var); |
| 83 | // error checking |
| 84 | if (!\is_numeric($val)) { |
| 85 | throw new \InvalidArgumentException("Value for `:` modifier must be numeric value [{$varname}:{$val}]"); |
| 86 | } |
| 87 | } |
| 88 | switch ($last = \substr($var, -1)) { |
| 89 | case '*': |
| 90 | case '%': |
| 91 | // there can be only 1 modifier per var |
| 92 | if ($modifier) { |
| 93 | throw new \InvalidArgumentException("Multiple modifiers per variable are not allowed [{$var}]"); |
| 94 | } |
| 95 | $modifier = $last; |
| 96 | $var = \substr($var, 0, -1); |
| 97 | break; |
| 98 | } |
| 99 | return $this->createVariableNode($var, ['modifier' => $modifier, 'value' => $val]); |
| 100 | } |
| 101 | protected function createVariableNode($token, $options = []) : Variable |
| 102 | { |
| 103 | return new Variable($token, $options); |
| 104 | } |
| 105 | protected function createExpressionNode($token, ?Operator\Abstraction $operator = null, array $vars = []) : Expression |
| 106 | { |
| 107 | return new Expression($token, $operator, $vars); |
| 108 | } |
| 109 | protected function createLiteralNode(string $token) : Node\Literal |
| 110 | { |
| 111 | return new Node\Literal($token); |
| 112 | } |
| 113 | protected function createOperatorNode($token) : Operator\Abstraction |
| 114 | { |
| 115 | return Operator\Abstraction::createById($token); |
| 116 | } |
| 117 | } |
| 118 |