1<?php 2 3/** 4 * Parses an array. 5 */ 6 7namespace PhpMyAdmin\SqlParser\Components; 8 9use PhpMyAdmin\SqlParser\Component; 10use PhpMyAdmin\SqlParser\Parser; 11use PhpMyAdmin\SqlParser\Token; 12use PhpMyAdmin\SqlParser\TokensList; 13 14/** 15 * Parses an array. 16 * 17 * @category Components 18 * 19 * @license https://www.gnu.org/licenses/gpl-2.0.txt GPL-2.0+ 20 */ 21class ArrayObj extends Component 22{ 23 /** 24 * The array that contains the unprocessed value of each token. 25 * 26 * @var array 27 */ 28 public $raw = array(); 29 30 /** 31 * The array that contains the processed value of each token. 32 * 33 * @var array 34 */ 35 public $values = array(); 36 37 /** 38 * Constructor. 39 * 40 * @param array $raw the unprocessed values 41 * @param array $values the processed values 42 */ 43 public function __construct(array $raw = array(), array $values = array()) 44 { 45 $this->raw = $raw; 46 $this->values = $values; 47 } 48 49 /** 50 * @param Parser $parser the parser that serves as context 51 * @param TokensList $list the list of tokens that are being parsed 52 * @param array $options parameters for parsing 53 * 54 * @return ArrayObj|Component[] 55 */ 56 public static function parse(Parser $parser, TokensList $list, array $options = array()) 57 { 58 $ret = empty($options['type']) ? new self() : array(); 59 60 /** 61 * The last raw expression. 62 * 63 * @var string 64 */ 65 $lastRaw = ''; 66 67 /** 68 * The last value. 69 * 70 * @var string 71 */ 72 $lastValue = ''; 73 74 /** 75 * Counts brackets. 76 * 77 * @var int 78 */ 79 $brackets = 0; 80 81 /** 82 * Last separator (bracket or comma). 83 * 84 * @var bool 85 */ 86 $isCommaLast = false; 87 88 for (; $list->idx < $list->count; ++$list->idx) { 89 /** 90 * Token parsed at this moment. 91 * 92 * @var Token 93 */ 94 $token = $list->tokens[$list->idx]; 95 96 // End of statement. 97 if ($token->type === Token::TYPE_DELIMITER) { 98 break; 99 } 100 101 // Skipping whitespaces and comments. 102 if (($token->type === Token::TYPE_WHITESPACE) 103 || ($token->type === Token::TYPE_COMMENT) 104 ) { 105 $lastRaw .= $token->token; 106 $lastValue = trim($lastValue) . ' '; 107 continue; 108 } 109 110 if (($brackets === 0) 111 && (($token->type !== Token::TYPE_OPERATOR) 112 || ($token->value !== '(')) 113 ) { 114 $parser->error('An opening bracket was expected.', $token); 115 break; 116 } 117 118 if ($token->type === Token::TYPE_OPERATOR) { 119 if ($token->value === '(') { 120 if (++$brackets === 1) { // 1 is the base level. 121 continue; 122 } 123 } elseif ($token->value === ')') { 124 if (--$brackets === 0) { // Array ended. 125 break; 126 } 127 } elseif ($token->value === ',') { 128 if ($brackets === 1) { 129 $isCommaLast = true; 130 if (empty($options['type'])) { 131 $ret->raw[] = trim($lastRaw); 132 $ret->values[] = trim($lastValue); 133 $lastRaw = $lastValue = ''; 134 } 135 } 136 continue; 137 } 138 } 139 140 if (empty($options['type'])) { 141 $lastRaw .= $token->token; 142 $lastValue .= $token->value; 143 } else { 144 $ret[] = $options['type']::parse( 145 $parser, 146 $list, 147 empty($options['typeOptions']) ? array() : $options['typeOptions'] 148 ); 149 } 150 } 151 152 // Handling last element. 153 // 154 // This is treated differently to treat the following cases: 155 // 156 // => array() 157 // (,) => array('', '') 158 // () => array() 159 // (a,) => array('a', '') 160 // (a) => array('a') 161 // 162 $lastRaw = trim($lastRaw); 163 if ((empty($options['type'])) 164 && ((strlen($lastRaw) > 0) || ($isCommaLast)) 165 ) { 166 $ret->raw[] = $lastRaw; 167 $ret->values[] = trim($lastValue); 168 } 169 170 return $ret; 171 } 172 173 /** 174 * @param ArrayObj|ArrayObj[] $component the component to be built 175 * @param array $options parameters for building 176 * 177 * @return string 178 */ 179 public static function build($component, array $options = array()) 180 { 181 if (is_array($component)) { 182 return implode(', ', $component); 183 } elseif (! empty($component->raw)) { 184 return '(' . implode(', ', $component->raw) . ')'; 185 } 186 187 return '(' . implode(', ', $component->values) . ')'; 188 } 189} 190