Prado\Web\UI\TTemplate::parse PHP Метод

parse() защищенный Метод

This template parser recognizes five types of data: regular string, well-formed component tags, well-formed property tags, directives, and expressions. The parsing result is returned as an array. Each array element can be of three types: - a string, 0: container index; 1: string content; - a component tag, 0: container index; 1: component type; 2: attributes (name=>value pairs) If a directive is found in the template, it will be parsed and can be retrieved via {@link getDirective}, which returns an array consisting of name-value pairs in the directive. Note, attribute names are treated as case-insensitive and will be turned into lower cases. Component and directive types are case-sensitive. Container index is the index to the array element that stores the container object. If an object has no container, its container index is -1.
protected parse ( $input )
    protected function parse($input)
    {
        $input = $this->preprocess($input);
        $tpl =& $this->_tpl;
        $n = preg_match_all(self::REGEX_RULES, $input, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
        $expectPropEnd = false;
        $textStart = 0;
        $stack = array();
        $container = -1;
        $matchEnd = 0;
        $c = 0;
        $this->_directive = null;
        for ($i = 0; $i < $n; ++$i) {
            $match =& $matches[$i];
            $str = $match[0][0];
            $matchStart = $match[0][1];
            $matchEnd = $matchStart + strlen($str) - 1;
            if (strpos($str, '<com:') === 0) {
                if ($expectPropEnd) {
                    continue;
                }
                if ($matchStart > $textStart) {
                    $tpl[$c++] = array($container, substr($input, $textStart, $matchStart - $textStart));
                }
                $textStart = $matchEnd + 1;
                $type = $match[1][0];
                $attributes = $this->parseAttributes($match[2][0], $match[2][1]);
                $this->validateAttributes($type, $attributes);
                $tpl[$c++] = array($container, $type, $attributes);
                if ($str[strlen($str) - 2] !== '/') {
                    $stack[] = $type;
                    $container = $c - 1;
                }
            } else {
                if (strpos($str, '</com:') === 0) {
                    if ($expectPropEnd) {
                        continue;
                    }
                    if ($matchStart > $textStart) {
                        $tpl[$c++] = array($container, substr($input, $textStart, $matchStart - $textStart));
                    }
                    $textStart = $matchEnd + 1;
                    $type = $match[1][0];
                    if (empty($stack)) {
                        throw new TConfigurationException('template_closingtag_unexpected', "</com:{$type}>");
                    }
                    $name = array_pop($stack);
                    if ($name !== $type) {
                        $tag = $name[0] === '@' ? '</prop:' . substr($name, 1) . '>' : "</com:{$name}>";
                        throw new TConfigurationException('template_closingtag_expected', $tag);
                    }
                    $container = $tpl[$container][0];
                } else {
                    if (strpos($str, '<%@') === 0) {
                        if ($expectPropEnd) {
                            continue;
                        }
                        if ($matchStart > $textStart) {
                            $tpl[$c++] = array($container, substr($input, $textStart, $matchStart - $textStart));
                        }
                        $textStart = $matchEnd + 1;
                        if (isset($tpl[0]) || $this->_directive !== null) {
                            throw new TConfigurationException('template_directive_nonunique');
                        }
                        $this->_directive = $this->parseAttributes($match[4][0], $match[4][1]);
                    } else {
                        if (strpos($str, '<%') === 0) {
                            if ($expectPropEnd) {
                                continue;
                            }
                            if ($matchStart > $textStart) {
                                $tpl[$c++] = array($container, substr($input, $textStart, $matchStart - $textStart));
                            }
                            $textStart = $matchEnd + 1;
                            $literal = trim($match[5][0]);
                            if ($str[2] === '=') {
                                // expression
                                $tpl[$c++] = array($container, array(TCompositeLiteral::TYPE_EXPRESSION, $literal));
                            } else {
                                if ($str[2] === '%') {
                                    // statements
                                    $tpl[$c++] = array($container, array(TCompositeLiteral::TYPE_STATEMENTS, $literal));
                                } else {
                                    if ($str[2] === '#') {
                                        $tpl[$c++] = array($container, array(TCompositeLiteral::TYPE_DATABINDING, $literal));
                                    } else {
                                        if ($str[2] === '$') {
                                            $tpl[$c++] = array($container, array(TCompositeLiteral::TYPE_EXPRESSION, "\$this->getApplication()->getParameters()->itemAt('{$literal}')"));
                                        } else {
                                            if ($str[2] === '~') {
                                                $tpl[$c++] = array($container, array(TCompositeLiteral::TYPE_EXPRESSION, "\$this->publishFilePath('{$this->_contextPath}/{$literal}')"));
                                            } else {
                                                if ($str[2] === '/') {
                                                    $tpl[$c++] = array($container, array(TCompositeLiteral::TYPE_EXPRESSION, "rtrim(dirname(\$this->getApplication()->getRequest()->getApplicationUrl()), '/').'/{$literal}'"));
                                                } else {
                                                    if ($str[2] === '[') {
                                                        $literal = strtr(trim(substr($literal, 0, strlen($literal) - 1)), array("'" => "\\'", "\\" => "\\\\"));
                                                        $tpl[$c++] = array($container, array(TCompositeLiteral::TYPE_EXPRESSION, "Prado::localize('{$literal}')"));
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        } else {
                            if (strpos($str, '<prop:') === 0) {
                                if (strrpos($str, '/>') === strlen($str) - 2) {
                                    if ($expectPropEnd) {
                                        continue;
                                    }
                                    if ($matchStart > $textStart) {
                                        $tpl[$c++] = array($container, substr($input, $textStart, $matchStart - $textStart));
                                    }
                                    $textStart = $matchEnd + 1;
                                    $prop = strtolower($match[6][0]);
                                    $attrs = $this->parseAttributes($match[7][0], $match[7][1]);
                                    $attributes = array();
                                    foreach ($attrs as $name => $value) {
                                        $attributes[$prop . '.' . $name] = $value;
                                    }
                                    $type = $tpl[$container][1];
                                    $this->validateAttributes($type, $attributes);
                                    foreach ($attributes as $name => $value) {
                                        if (isset($tpl[$container][2][$name])) {
                                            throw new TConfigurationException('template_property_duplicated', $name);
                                        }
                                        $tpl[$container][2][$name] = $value;
                                    }
                                } else {
                                    $prop = strtolower($match[3][0]);
                                    $stack[] = '@' . $prop;
                                    if (!$expectPropEnd) {
                                        if ($matchStart > $textStart) {
                                            $tpl[$c++] = array($container, substr($input, $textStart, $matchStart - $textStart));
                                        }
                                        $textStart = $matchEnd + 1;
                                        $expectPropEnd = true;
                                    }
                                }
                            } else {
                                if (strpos($str, '</prop:') === 0) {
                                    $prop = strtolower($match[3][0]);
                                    if (empty($stack)) {
                                        throw new TConfigurationException('template_closingtag_unexpected', "</prop:{$prop}>");
                                    }
                                    $name = array_pop($stack);
                                    if ($name !== '@' . $prop) {
                                        $tag = $name[0] === '@' ? '</prop:' . substr($name, 1) . '>' : "</com:{$name}>";
                                        throw new TConfigurationException('template_closingtag_expected', $tag);
                                    }
                                    if (($last = count($stack)) < 1 || $stack[$last - 1][0] !== '@') {
                                        if ($matchStart > $textStart) {
                                            $value = substr($input, $textStart, $matchStart - $textStart);
                                            if (substr($prop, -8, 8) === 'template') {
                                                $value = $this->parseTemplateProperty($value, $textStart);
                                            } else {
                                                $value = $this->parseAttribute($value);
                                            }
                                            if ($container >= 0) {
                                                $type = $tpl[$container][1];
                                                $this->validateAttributes($type, array($prop => $value));
                                                if (isset($tpl[$container][2][$prop])) {
                                                    throw new TConfigurationException('template_property_duplicated', $prop);
                                                }
                                                $tpl[$container][2][$prop] = $value;
                                            } else {
                                                // a property for the template control
                                                $this->_directive[$prop] = $value;
                                            }
                                            $textStart = $matchEnd + 1;
                                        }
                                        $expectPropEnd = false;
                                    }
                                } else {
                                    if (strpos($str, '<!--') === 0) {
                                        if ($expectPropEnd) {
                                            throw new TConfigurationException('template_comments_forbidden');
                                        }
                                        if ($matchStart > $textStart) {
                                            $tpl[$c++] = array($container, substr($input, $textStart, $matchStart - $textStart));
                                        }
                                        $textStart = $matchEnd + 1;
                                    } else {
                                        throw new TConfigurationException('template_matching_unexpected', $match);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        if (!empty($stack)) {
            $name = array_pop($stack);
            $tag = $name[0] === '@' ? '</prop:' . substr($name, 1) . '>' : "</com:{$name}>";
            throw new TConfigurationException('template_closingtag_expected', $tag);
        }
        if ($textStart < strlen($input)) {
            $tpl[$c++] = array($container, substr($input, $textStart));
        }
        /*
        		catch(\Exception $e)
        		{
        			if(($e instanceof TException) && ($e instanceof TTemplateException))
        				throw $e;
        			if($matchEnd===0)
        				$line=$this->_startingLine+1;
        			else
        				$line=$this->_startingLine+count(explode("\n",substr($input,0,$matchEnd+1)));
        			$this->handleException($e,$line,$input);
        		} */
        if ($this->_directive === null) {
            $this->_directive = array();
        }
        // optimization by merging consecutive strings, expressions, statements and bindings
        $objects = array();
        $parent = null;
        $merged = array();
        foreach ($tpl as $id => $object) {
            if (isset($object[2]) || $object[0] !== $parent) {
                if ($parent !== null) {
                    if (count($merged[1]) === 1 && is_string($merged[1][0])) {
                        $objects[$id - 1] = array($merged[0], $merged[1][0]);
                    } else {
                        $objects[$id - 1] = array($merged[0], new TCompositeLiteral($merged[1]));
                    }
                }
                if (isset($object[2])) {
                    $parent = null;
                    $objects[$id] = $object;
                } else {
                    $parent = $object[0];
                    $merged = array($parent, array($object[1]));
                }
            } else {
                $merged[1][] = $object[1];
            }
        }
        if ($parent !== null) {
            if (count($merged[1]) === 1 && is_string($merged[1][0])) {
                $objects[$id] = array($merged[0], $merged[1][0]);
            } else {
                $objects[$id] = array($merged[0], new TCompositeLiteral($merged[1]));
            }
        }
        $tpl = $objects;
        return $objects;
    }