Dotclear

Changeset 1101:7273894e61b8


Ignore:
Timestamp:
02/15/13 08:35:19 (12 years ago)
Author:
Dsls <dsls@…>
Branch:
twig
Children:
1106:a4487f3ca4b4, 1147:2e5cb79e4782
Message:

Twig 1.12.2

Location:
inc/libs/twig
Files:
9 added
41 edited

Legend:

Unmodified
Added
Removed
  • inc/libs/twig/CHANGELOG

    r991 r1101  
     1* 1.12.2 (2013-02-09) 
     2 
     3 * fixed the timezone used by the date filter and function when the given date contains a timezone (like 2010-01-28T15:00:00+02:00) 
     4 * fixed globals when getGlobals is called early on 
     5 * added the first and last filter 
     6 
     7* 1.12.1 (2013-01-15) 
     8 
     9 * added support for object instances as the second argument of the constant function 
     10 * relaxed globals management to avoid a BC break 
     11 * added support for {{ some_string[:2] }} 
     12 
     13* 1.12.0 (2013-01-08) 
     14 
     15 * added verbatim as an alias for the raw tag to avoid confusion with the raw filter 
     16 * fixed registration of tests and functions as anonymous functions 
     17 * fixed globals management 
     18 
     19* 1.12.0-RC1 (2012-12-29) 
     20 
     21 * added an include function (does the same as the include tag but in a more flexible way) 
     22 * added the ability to use any PHP callable to define filters, functions, and tests 
     23 * added a syntax error when using a loop variable that is not defined 
     24 * added the ability to set default values for macro arguments 
     25 * added support for named arguments for filters, tests, and functions 
     26 * moved filters/functions/tests syntax errors to the parser 
     27 * added support for extended ternary operator syntaxes 
     28 
    129* 1.11.1 (2012-11-11) 
    230 
  • inc/libs/twig/Compiler.php

    r991 r1101  
    257257    public function outdent($step = 1) 
    258258    { 
    259         // can't outdent by more steps that the current indentation level 
     259        // can't outdent by more steps than the current indentation level 
    260260        if ($this->indentation < $step) { 
    261261            throw new LogicException('Unable to call outdent() as the indentation would become negative'); 
  • inc/libs/twig/CompilerInterface.php

    r991 r1101  
    1515 * @package    twig 
    1616 * @author     Fabien Potencier <fabien@symfony.com> 
     17 * @deprecated since 1.12 (to be removed in 2.0) 
    1718 */ 
    1819interface Twig_CompilerInterface 
  • inc/libs/twig/Environment.php

    r991 r1101  
    1818class Twig_Environment 
    1919{ 
    20     const VERSION = '1.11.1'; 
     20    const VERSION = '1.12.2'; 
    2121 
    2222    protected $charset; 
     
    3737    protected $globals; 
    3838    protected $runtimeInitialized; 
     39    protected $extensionInitialized; 
    3940    protected $loadedTemplates; 
    4041    protected $strictVariables; 
     
    103104        $this->baseTemplateClass  = $options['base_template_class']; 
    104105        $this->autoReload         = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload']; 
    105         $this->extensions         = array( 
    106             'core'      => new Twig_Extension_Core(), 
    107             'escaper'   => new Twig_Extension_Escaper($options['autoescape']), 
    108             'optimizer' => new Twig_Extension_Optimizer($options['optimizations']), 
    109         ); 
    110106        $this->strictVariables    = (bool) $options['strict_variables']; 
    111107        $this->runtimeInitialized = false; 
     
    113109        $this->functionCallbacks = array(); 
    114110        $this->filterCallbacks = array(); 
    115         $this->staging = array( 
    116             'functions'     => array(), 
    117             'filters'       => array(), 
    118             'tests'         => array(), 
    119             'token_parsers' => array(), 
    120             'visitors'      => array(), 
    121             'globals'       => array(), 
    122         ); 
     111 
     112        $this->addExtension(new Twig_Extension_Core()); 
     113        $this->addExtension(new Twig_Extension_Escaper($options['autoescape'])); 
     114        $this->addExtension(new Twig_Extension_Optimizer($options['optimizations'])); 
     115        $this->extensionInitialized = false; 
     116        $this->staging = new Twig_Extension_Staging(); 
    123117    } 
    124118 
     
    270264    public function getTemplateClass($name, $index = null) 
    271265    { 
    272         return $this->templateClassPrefix.md5($this->loader->getCacheKey($name)).(null === $index ? '' : '_'.$index); 
     266        return $this->templateClassPrefix.md5($this->getLoader()->getCacheKey($name)).(null === $index ? '' : '_'.$index); 
    273267    } 
    274268 
     
    325319        if (!class_exists($cls, false)) { 
    326320            if (false === $cache = $this->getCacheFilename($name)) { 
    327                 eval('?>'.$this->compileSource($this->loader->getSource($name), $name)); 
     321                eval('?>'.$this->compileSource($this->getLoader()->getSource($name), $name)); 
    328322            } else { 
    329323                if (!is_file($cache) || ($this->isAutoReload() && !$this->isTemplateFresh($name, filemtime($cache)))) { 
    330                     $this->writeCacheFile($cache, $this->compileSource($this->loader->getSource($name), $name)); 
     324                    $this->writeCacheFile($cache, $this->compileSource($this->getLoader()->getSource($name), $name)); 
    331325                } 
    332326 
     
    363357        } 
    364358 
    365         return $this->loader->isFresh($name, $time); 
     359        return $this->getLoader()->isFresh($name, $time); 
    366360    } 
    367361 
     
    560554    public function getLoader() 
    561555    { 
     556        if (null === $this->loader) { 
     557            throw new LogicException('You must set a loader first.'); 
     558        } 
     559 
    562560        return $this->loader; 
    563561    } 
     
    630628    public function addExtension(Twig_ExtensionInterface $extension) 
    631629    { 
     630        if ($this->extensionInitialized) { 
     631            throw new LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $extension->getName())); 
     632        } 
     633 
    632634        $this->extensions[$extension->getName()] = $extension; 
    633         $this->parsers = null; 
    634         $this->visitors = null; 
    635         $this->filters = null; 
    636         $this->tests = null; 
    637         $this->functions = null; 
    638         $this->globals = null; 
    639635    } 
    640636 
     
    642638     * Removes an extension by name. 
    643639     * 
     640     * This method is deprecated and you should not use it. 
     641     * 
    644642     * @param string $name The extension name 
     643     * 
     644     * @deprecated since 1.12 (to be removed in 2.0) 
    645645     */ 
    646646    public function removeExtension($name) 
    647647    { 
     648        if ($this->extensionInitialized) { 
     649            throw new LogicException(sprintf('Unable to remove extension "%s" as extensions have already been initialized.', $name)); 
     650        } 
     651 
    648652        unset($this->extensions[$name]); 
    649         $this->parsers = null; 
    650         $this->visitors = null; 
    651         $this->filters = null; 
    652         $this->tests = null; 
    653         $this->functions = null; 
    654         $this->globals = null; 
    655653    } 
    656654 
     
    684682    public function addTokenParser(Twig_TokenParserInterface $parser) 
    685683    { 
    686         $this->staging['token_parsers'][] = $parser; 
    687         $this->parsers = null; 
     684        if ($this->extensionInitialized) { 
     685            throw new LogicException('Unable to add a token parser as extensions have already been initialized.'); 
     686        } 
     687 
     688        $this->staging->addTokenParser($parser); 
    688689    } 
    689690 
     
    695696    public function getTokenParsers() 
    696697    { 
    697         if (null === $this->parsers) { 
    698             $this->parsers = new Twig_TokenParserBroker(); 
    699  
    700             if (isset($this->staging['token_parsers'])) { 
    701                 foreach ($this->staging['token_parsers'] as $parser) { 
    702                     $this->parsers->addTokenParser($parser); 
    703                 } 
    704             } 
    705  
    706             foreach ($this->getExtensions() as $extension) { 
    707                 $parsers = $extension->getTokenParsers(); 
    708                 foreach ($parsers as $parser) { 
    709                     if ($parser instanceof Twig_TokenParserInterface) { 
    710                         $this->parsers->addTokenParser($parser); 
    711                     } elseif ($parser instanceof Twig_TokenParserBrokerInterface) { 
    712                         $this->parsers->addTokenParserBroker($parser); 
    713                     } else { 
    714                         throw new LogicException('getTokenParsers() must return an array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances'); 
    715                     } 
    716                 } 
    717             } 
     698        if (!$this->extensionInitialized) { 
     699            $this->initExtensions(); 
    718700        } 
    719701 
     
    747729    public function addNodeVisitor(Twig_NodeVisitorInterface $visitor) 
    748730    { 
    749         $this->staging['visitors'][] = $visitor; 
    750         $this->visitors = null; 
     731        if ($this->extensionInitialized) { 
     732            throw new LogicException('Unable to add a node visitor as extensions have already been initialized.', $extension->getName()); 
     733        } 
     734 
     735        $this->staging->addNodeVisitor($visitor); 
    751736    } 
    752737 
     
    758743    public function getNodeVisitors() 
    759744    { 
    760         if (null === $this->visitors) { 
    761             foreach ($this->getExtensions() as $extension) { 
    762                 foreach ($extension->getNodeVisitors() as $visitor) { 
    763                     $this->addNodeVisitor($visitor); 
    764                 } 
    765             } 
    766  
    767             $this->visitors = $this->staging['visitors']; 
     745        if (!$this->extensionInitialized) { 
     746            $this->initExtensions(); 
    768747        } 
    769748 
     
    774753     * Registers a Filter. 
    775754     * 
    776      * @param string               $name   The filter name 
    777      * @param Twig_FilterInterface $filter A Twig_FilterInterface instance 
    778      */ 
    779     public function addFilter($name, Twig_FilterInterface $filter) 
    780     { 
    781         $this->staging['filters'][$name] = $filter; 
    782         $this->filters = null; 
     755     * @param string|Twig_SimpleFilter               $name   The filter name or a Twig_SimpleFilter instance 
     756     * @param Twig_FilterInterface|Twig_SimpleFilter $filter A Twig_FilterInterface instance or a Twig_SimpleFilter instance 
     757     */ 
     758    public function addFilter($name, $filter = null) 
     759    { 
     760        if ($this->extensionInitialized) { 
     761            throw new LogicException(sprintf('Unable to add filter "%s" as extensions have already been initialized.', $name)); 
     762        } 
     763 
     764        if (!$name instanceof Twig_SimpleFilter && !($filter instanceof Twig_SimpleFilter || $filter instanceof Twig_FilterInterface)) { 
     765            throw new LogicException('A filter must be an instance of Twig_FilterInterface or Twig_SimpleFilter'); 
     766        } 
     767 
     768        if ($name instanceof Twig_SimpleFilter) { 
     769            $filter = $name; 
     770            $name = $filter->getName(); 
     771        } 
     772 
     773        $this->staging->addFilter($name, $filter); 
    783774    } 
    784775 
     
    791782     * @param string $name The filter name 
    792783     * 
    793      * @return Twig_Filter|false A Twig_Filter instance or false if the filter does not exists 
     784     * @return Twig_Filter|false A Twig_Filter instance or false if the filter does not exist 
    794785     */ 
    795786    public function getFilter($name) 
    796787    { 
    797         if (null === $this->filters) { 
    798             $this->getFilters(); 
     788        if (!$this->extensionInitialized) { 
     789            $this->initExtensions(); 
    799790        } 
    800791 
     
    841832    public function getFilters() 
    842833    { 
    843         if (null === $this->filters) { 
    844             foreach ($this->getExtensions() as $extension) { 
    845                 foreach ($extension->getFilters() as $name => $filter) { 
    846                     $this->addFilter($name, $filter); 
    847                 } 
    848             } 
    849  
    850             $this->filters = $this->staging['filters']; 
     834        if (!$this->extensionInitialized) { 
     835            $this->initExtensions(); 
    851836        } 
    852837 
     
    857842     * Registers a Test. 
    858843     * 
    859      * @param string             $name The test name 
    860      * @param Twig_TestInterface $test A Twig_TestInterface instance 
    861      */ 
    862     public function addTest($name, Twig_TestInterface $test) 
    863     { 
    864         $this->staging['tests'][$name] = $test; 
    865         $this->tests = null; 
     844     * @param string|Twig_SimpleTest             $name The test name or a Twig_SimpleTest instance 
     845     * @param Twig_TestInterface|Twig_SimpleTest $test A Twig_TestInterface instance or a Twig_SimpleTest instance 
     846     */ 
     847    public function addTest($name, $test = null) 
     848    { 
     849        if ($this->extensionInitialized) { 
     850            throw new LogicException(sprintf('Unable to add test "%s" as extensions have already been initialized.', $name)); 
     851        } 
     852 
     853        if (!$name instanceof Twig_SimpleTest && !($test instanceof Twig_SimpleTest || $test instanceof Twig_TestInterface)) { 
     854            throw new LogicException('A test must be an instance of Twig_TestInterface or Twig_SimpleTest'); 
     855        } 
     856 
     857        if ($name instanceof Twig_SimpleTest) { 
     858            $test = $name; 
     859            $name = $test->getName(); 
     860        } 
     861 
     862        $this->staging->addTest($name, $test); 
    866863    } 
    867864 
     
    873870    public function getTests() 
    874871    { 
    875         if (null === $this->tests) { 
    876             foreach ($this->getExtensions() as $extension) { 
    877                 foreach ($extension->getTests() as $name => $test) { 
    878                     $this->addTest($name, $test); 
    879                 } 
    880             } 
    881  
    882             $this->tests = $this->staging['tests']; 
     872        if (!$this->extensionInitialized) { 
     873            $this->initExtensions(); 
    883874        } 
    884875 
     
    887878 
    888879    /** 
     880     * Gets a test by name. 
     881     * 
     882     * @param string $name The test name 
     883     * 
     884     * @return Twig_Test|false A Twig_Test instance or false if the test does not exist 
     885     */ 
     886    public function getTest($name) 
     887    { 
     888        if (!$this->extensionInitialized) { 
     889            $this->initExtensions(); 
     890        } 
     891 
     892        if (isset($this->tests[$name])) { 
     893            return $this->tests[$name]; 
     894        } 
     895 
     896        return false; 
     897    } 
     898 
     899    /** 
    889900     * Registers a Function. 
    890901     * 
    891      * @param string                 $name     The function name 
    892      * @param Twig_FunctionInterface $function A Twig_FunctionInterface instance 
    893      */ 
    894     public function addFunction($name, Twig_FunctionInterface $function) 
    895     { 
    896         $this->staging['functions'][$name] = $function; 
    897         $this->functions = null; 
     902     * @param string|Twig_SimpleFunction                 $name     The function name or a Twig_SimpleFunction instance 
     903     * @param Twig_FunctionInterface|Twig_SimpleFunction $function A Twig_FunctionInterface instance or a Twig_SimpleFunction instance 
     904     */ 
     905    public function addFunction($name, $function = null) 
     906    { 
     907        if ($this->extensionInitialized) { 
     908            throw new LogicException(sprintf('Unable to add function "%s" as extensions have already been initialized.', $name)); 
     909        } 
     910 
     911        if (!$name instanceof Twig_SimpleFunction && !($function instanceof Twig_SimpleFunction || $function instanceof Twig_FunctionInterface)) { 
     912            throw new LogicException('A function must be an instance of Twig_FunctionInterface or Twig_SimpleFunction'); 
     913        } 
     914 
     915        if ($name instanceof Twig_SimpleFunction) { 
     916            $function = $name; 
     917            $name = $function->getName(); 
     918        } 
     919 
     920        $this->staging->addFunction($name, $function); 
    898921    } 
    899922 
     
    906929     * @param string $name function name 
    907930     * 
    908      * @return Twig_Function|false A Twig_Function instance or false if the function does not exists 
     931     * @return Twig_Function|false A Twig_Function instance or false if the function does not exist 
    909932     */ 
    910933    public function getFunction($name) 
    911934    { 
    912         if (null === $this->functions) { 
    913             $this->getFunctions(); 
     935        if (!$this->extensionInitialized) { 
     936            $this->initExtensions(); 
    914937        } 
    915938 
     
    956979    public function getFunctions() 
    957980    { 
    958         if (null === $this->functions) { 
    959             foreach ($this->getExtensions() as $extension) { 
    960                 foreach ($extension->getFunctions() as $name => $function) { 
    961                     $this->addFunction($name, $function); 
    962                 } 
    963             } 
    964  
    965             $this->functions = $this->staging['functions']; 
     981        if (!$this->extensionInitialized) { 
     982            $this->initExtensions(); 
    966983        } 
    967984 
     
    971988    /** 
    972989     * Registers a Global. 
     990     * 
     991     * New globals can be added before compiling or rendering a template; 
     992     * but after, you can only update existing globals. 
    973993     * 
    974994     * @param string $name  The global name 
     
    977997    public function addGlobal($name, $value) 
    978998    { 
    979         $this->staging['globals'][$name] = $value; 
    980         $this->globals = null; 
     999        if ($this->extensionInitialized || $this->runtimeInitialized) { 
     1000            if (null === $this->globals) { 
     1001                $this->globals = $this->initGlobals(); 
     1002            } 
     1003 
     1004            /* This condition must be uncommented in Twig 2.0 
     1005            if (!array_key_exists($name, $this->globals)) { 
     1006                throw new LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name)); 
     1007            } 
     1008            */ 
     1009        } 
     1010 
     1011        if ($this->extensionInitialized || $this->runtimeInitialized) { 
     1012            // update the value 
     1013            $this->globals[$name] = $value; 
     1014        } else { 
     1015            $this->staging->addGlobal($name, $value); 
     1016        } 
    9811017    } 
    9821018 
     
    9881024    public function getGlobals() 
    9891025    { 
     1026        if (!$this->runtimeInitialized && !$this->extensionInitialized) { 
     1027            return $this->initGlobals(); 
     1028        } 
     1029 
    9901030        if (null === $this->globals) { 
    991             $this->globals = isset($this->staging['globals']) ? $this->staging['globals'] : array(); 
    992             foreach ($this->getExtensions() as $extension) { 
    993                 $this->globals = array_merge($this->globals, $extension->getGlobals()); 
    994             } 
     1031            $this->globals = $this->initGlobals(); 
    9951032        } 
    9961033 
     
    10251062    public function getUnaryOperators() 
    10261063    { 
    1027         if (null === $this->unaryOperators) { 
    1028             $this->initOperators(); 
     1064        if (!$this->extensionInitialized) { 
     1065            $this->initExtensions(); 
    10291066        } 
    10301067 
     
    10391076    public function getBinaryOperators() 
    10401077    { 
    1041         if (null === $this->binaryOperators) { 
    1042             $this->initOperators(); 
     1078        if (!$this->extensionInitialized) { 
     1079            $this->initExtensions(); 
    10431080        } 
    10441081 
     
    10601097    } 
    10611098 
    1062     protected function initOperators() 
    1063     { 
     1099    protected function initGlobals() 
     1100    { 
     1101        $globals = array(); 
     1102        foreach ($this->extensions as $extension) { 
     1103            $globals = array_merge($globals, $extension->getGlobals()); 
     1104        } 
     1105 
     1106        return array_merge($globals, $this->staging->getGlobals()); 
     1107    } 
     1108 
     1109    protected function initExtensions() 
     1110    { 
     1111        if ($this->extensionInitialized) { 
     1112            return; 
     1113        } 
     1114 
     1115        $this->extensionInitialized = true; 
     1116        $this->parsers = new Twig_TokenParserBroker(); 
     1117        $this->filters = array(); 
     1118        $this->functions = array(); 
     1119        $this->tests = array(); 
     1120        $this->visitors = array(); 
    10641121        $this->unaryOperators = array(); 
    10651122        $this->binaryOperators = array(); 
    1066         foreach ($this->getExtensions() as $extension) { 
    1067             $operators = $extension->getOperators(); 
    1068  
    1069             if (!$operators) { 
    1070                 continue; 
    1071             } 
    1072  
     1123 
     1124        foreach ($this->extensions as $extension) { 
     1125            $this->initExtension($extension); 
     1126        } 
     1127        $this->initExtension($this->staging); 
     1128    } 
     1129 
     1130    protected function initExtension(Twig_ExtensionInterface $extension) 
     1131    { 
     1132        // filters 
     1133        foreach ($extension->getFilters() as $name => $filter) { 
     1134            if ($name instanceof Twig_SimpleFilter) { 
     1135                $filter = $name; 
     1136                $name = $filter->getName(); 
     1137            } elseif ($filter instanceof Twig_SimpleFilter) { 
     1138                $name = $filter->getName(); 
     1139            } 
     1140 
     1141            $this->filters[$name] = $filter; 
     1142        } 
     1143 
     1144        // functions 
     1145        foreach ($extension->getFunctions() as $name => $function) { 
     1146            if ($name instanceof Twig_SimpleFunction) { 
     1147                $function = $name; 
     1148                $name = $function->getName(); 
     1149            } elseif ($function instanceof Twig_SimpleFunction) { 
     1150                $name = $function->getName(); 
     1151            } 
     1152 
     1153            $this->functions[$name] = $function; 
     1154        } 
     1155 
     1156        // tests 
     1157        foreach ($extension->getTests() as $name => $test) { 
     1158            if ($name instanceof Twig_SimpleTest) { 
     1159                $test = $name; 
     1160                $name = $test->getName(); 
     1161            } elseif ($test instanceof Twig_SimpleTest) { 
     1162                $name = $test->getName(); 
     1163            } 
     1164 
     1165            $this->tests[$name] = $test; 
     1166        } 
     1167 
     1168        // token parsers 
     1169        foreach ($extension->getTokenParsers() as $parser) { 
     1170            if ($parser instanceof Twig_TokenParserInterface) { 
     1171                $this->parsers->addTokenParser($parser); 
     1172            } elseif ($parser instanceof Twig_TokenParserBrokerInterface) { 
     1173                $this->parsers->addTokenParserBroker($parser); 
     1174            } else { 
     1175                throw new LogicException('getTokenParsers() must return an array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances'); 
     1176            } 
     1177        } 
     1178 
     1179        // node visitors 
     1180        foreach ($extension->getNodeVisitors() as $visitor) { 
     1181            $this->visitors[] = $visitor; 
     1182        } 
     1183 
     1184        // operators 
     1185        if ($operators = $extension->getOperators()) { 
    10731186            if (2 !== count($operators)) { 
    10741187                throw new InvalidArgumentException(sprintf('"%s::getOperators()" does not return a valid operators array.', get_class($extension))); 
  • inc/libs/twig/ExistsLoaderInterface.php

    r991 r1101  
    1515 * @package    twig 
    1616 * @author     Florin Patan <florinpatan@gmail.com> 
     17 * @deprecated since 1.12 (to be removed in 2.0) 
    1718 */ 
    1819interface Twig_ExistsLoaderInterface 
  • inc/libs/twig/ExpressionParser.php

    r991 r1101  
    9090        while ($this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '?')) { 
    9191            $this->parser->getStream()->next(); 
    92             $expr2 = $this->parseExpression(); 
    93             $this->parser->getStream()->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'The ternary operator must have a default value'); 
    94             $expr3 = $this->parseExpression(); 
     92            if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ':')) { 
     93                $expr2 = $this->parseExpression(); 
     94                if ($this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ':')) { 
     95                    $this->parser->getStream()->next(); 
     96                    $expr3 = $this->parseExpression(); 
     97                } else { 
     98                    $expr3 = new Twig_Node_Expression_Constant('', $this->parser->getCurrentToken()->getLine()); 
     99                } 
     100            } else { 
     101                $this->parser->getStream()->next(); 
     102                $expr2 = $expr; 
     103                $expr3 = $this->parseExpression(); 
     104            } 
    95105 
    96106            $expr = new Twig_Node_Expression_Conditional($expr, $expr2, $expr3, $this->parser->getCurrentToken()->getLine()); 
     
    288298    public function getFunctionNode($name, $line) 
    289299    { 
    290         $args = $this->parseArguments(); 
    291300        switch ($name) { 
    292301            case 'parent': 
     302                $args = $this->parseArguments(); 
    293303                if (!count($this->parser->getBlockStack())) { 
    294304                    throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden', $line, $this->parser->getFilename()); 
     
    301311                return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line); 
    302312            case 'block': 
    303                 return new Twig_Node_Expression_BlockReference($args->getNode(0), false, $line); 
     313                return new Twig_Node_Expression_BlockReference($this->parseArguments()->getNode(0), false, $line); 
    304314            case 'attribute': 
     315                $args = $this->parseArguments(); 
    305316                if (count($args) < 2) { 
    306317                    throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes)', $line, $this->parser->getFilename()); 
     
    311322                if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) { 
    312323                    $arguments = new Twig_Node_Expression_Array(array(), $line); 
    313                     foreach ($args as $n) { 
     324                    foreach ($this->parseArguments() as $n) { 
    314325                        $arguments->addElement($n); 
    315326                    } 
     
    321332                } 
    322333 
    323                 $class = $this->getFunctionNodeClass($name); 
     334                $args = $this->parseArguments(true); 
     335                $class = $this->getFunctionNodeClass($name, $line); 
    324336 
    325337                return new $class($name, $args, $line); 
     
    354366                throw new Twig_Error_Syntax('Expected name or number', $lineno, $this->parser->getFilename()); 
    355367            } 
     368 
     369            if ($node instanceof Twig_Node_Expression_Name && null !== $alias = $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) { 
     370                if (!$arg instanceof Twig_Node_Expression_Constant) { 
     371                    throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s")', $node->getAttribute('name')), $token->getLine(), $this->parser->getFilename()); 
     372                } 
     373 
     374                $node = new Twig_Node_Expression_MethodCall($node, 'get'.$arg->getAttribute('value'), $arguments, $lineno); 
     375                $node->setAttribute('safe', true); 
     376 
     377                return $node; 
     378            } 
    356379        } else { 
    357380            $type = Twig_TemplateInterface::ARRAY_CALL; 
    358381 
    359             $arg = $this->parseExpression(); 
    360  
    361382            // slice? 
     383            $slice = false; 
    362384            if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) { 
     385                $slice = true; 
     386                $arg = new Twig_Node_Expression_Constant(0, $token->getLine()); 
     387            } else { 
     388                $arg = $this->parseExpression(); 
     389            } 
     390 
     391            if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) { 
     392                $slice = true; 
    363393                $stream->next(); 
    364  
     394            } 
     395 
     396            if ($slice) { 
    365397                if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) { 
    366398                    $length = new Twig_Node_Expression_Constant(null, $token->getLine()); 
     
    369401                } 
    370402 
    371                 $class = $this->getFilterNodeClass('slice'); 
     403                $class = $this->getFilterNodeClass('slice', $token->getLine()); 
    372404                $arguments = new Twig_Node(array($arg, $length)); 
    373405                $filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine()); 
     
    379411 
    380412            $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']'); 
    381         } 
    382  
    383         if ($node instanceof Twig_Node_Expression_Name && null !== $alias = $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) { 
    384             $node = new Twig_Node_Expression_MethodCall($node, 'get'.$arg->getAttribute('value'), $arguments, $lineno); 
    385             $node->setAttribute('safe', true); 
    386  
    387             return $node; 
    388413        } 
    389414 
     
    407432                $arguments = new Twig_Node(); 
    408433            } else { 
    409                 $arguments = $this->parseArguments(); 
    410             } 
    411  
    412             $class = $this->getFilterNodeClass($name->getAttribute('value')); 
     434                $arguments = $this->parseArguments(true); 
     435            } 
     436 
     437            $class = $this->getFilterNodeClass($name->getAttribute('value'), $token->getLine()); 
    413438 
    414439            $node = new $class($node, $name, $arguments, $token->getLine(), $tag); 
     
    424449    } 
    425450 
    426     public function parseArguments() 
     451    /** 
     452     * Parses arguments. 
     453     * 
     454     * @param Boolean $namedArguments Whether to allow named arguments or not 
     455     * @param Boolean $definition     Whether we are parsing arguments for a function definition 
     456     */ 
     457    public function parseArguments($namedArguments = false, $definition = false) 
    427458    { 
    428459        $args = array(); 
    429460        $stream = $this->parser->getStream(); 
    430461 
    431         $stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must be opened by a parenthesis'); 
     462        $stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis'); 
    432463        while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ')')) { 
    433464            if (!empty($args)) { 
    434465                $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma'); 
    435466            } 
    436             $args[] = $this->parseExpression(); 
     467 
     468            if ($definition) { 
     469                $token = $stream->expect(Twig_Token::NAME_TYPE, null, 'An argument must be a name'); 
     470                $value = new Twig_Node_Expression_Name($token->getValue(), $this->parser->getCurrentToken()->getLine()); 
     471            } else { 
     472                $value = $this->parseExpression(); 
     473            } 
     474 
     475            $name = null; 
     476            if ($namedArguments && $stream->test(Twig_Token::OPERATOR_TYPE, '=')) { 
     477                $token = $stream->next(); 
     478                if (!$value instanceof Twig_Node_Expression_Name) { 
     479                    throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given', get_class($value)), $token->getLine(), $this->parser->getFilename()); 
     480                } 
     481                $name = $value->getAttribute('name'); 
     482 
     483                if ($definition) { 
     484                    $value = $this->parsePrimaryExpression(); 
     485 
     486                    if (!$this->checkConstantExpression($value)) { 
     487                        throw new Twig_Error_Syntax(sprintf('A default value for an argument must be a constant (a boolean, a string, a number, or an array).'), $token->getLine(), $this->parser->getFilename()); 
     488                    } 
     489                } else { 
     490                    $value = $this->parseExpression(); 
     491                } 
     492            } 
     493 
     494            if ($definition) { 
     495                if (null === $name) { 
     496                    $name = $value->getAttribute('name'); 
     497                    $value = new Twig_Node_Expression_Constant(null, $this->parser->getCurrentToken()->getLine()); 
     498                } 
     499                $args[$name] = $value; 
     500            } else { 
     501                if (null === $name) { 
     502                    $args[] = $value; 
     503                } else { 
     504                    $args[$name] = $value; 
     505                } 
     506            } 
    437507        } 
    438508        $stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis'); 
     
    474544    } 
    475545 
    476     protected function getFunctionNodeClass($name) 
    477     { 
    478         $functionMap = $this->parser->getEnvironment()->getFunctions(); 
    479         if (isset($functionMap[$name]) && $functionMap[$name] instanceof Twig_Function_Node) { 
    480             return $functionMap[$name]->getClass(); 
    481         } 
    482  
    483         return 'Twig_Node_Expression_Function'; 
    484     } 
    485  
    486     protected function getFilterNodeClass($name) 
    487     { 
    488         $filterMap = $this->parser->getEnvironment()->getFilters(); 
    489         if (isset($filterMap[$name]) && $filterMap[$name] instanceof Twig_Filter_Node) { 
    490             return $filterMap[$name]->getClass(); 
    491         } 
    492  
    493         return 'Twig_Node_Expression_Filter'; 
     546    protected function getFunctionNodeClass($name, $line) 
     547    { 
     548        $env = $this->parser->getEnvironment(); 
     549 
     550        if (false === $function = $env->getFunction($name)) { 
     551            $message = sprintf('The function "%s" does not exist', $name); 
     552            if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFunctions()))) { 
     553                $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); 
     554            } 
     555 
     556            throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename()); 
     557        } 
     558 
     559        if ($function instanceof Twig_SimpleFunction) { 
     560            return $function->getNodeClass(); 
     561        } 
     562 
     563        return $function instanceof Twig_Function_Node ? $function->getClass() : 'Twig_Node_Expression_Function'; 
     564    } 
     565 
     566    protected function getFilterNodeClass($name, $line) 
     567    { 
     568        $env = $this->parser->getEnvironment(); 
     569 
     570        if (false === $filter = $env->getFilter($name)) { 
     571            $message = sprintf('The filter "%s" does not exist', $name); 
     572            if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFilters()))) { 
     573                $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); 
     574            } 
     575 
     576            throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename()); 
     577        } 
     578 
     579        if ($filter instanceof Twig_SimpleFilter) { 
     580            return $filter->getNodeClass(); 
     581        } 
     582 
     583        return $filter instanceof Twig_Filter_Node ? $filter->getClass() : 'Twig_Node_Expression_Filter'; 
     584    } 
     585 
     586    // checks that the node only contains "constant" elements 
     587    protected function checkConstantExpression(Twig_NodeInterface $node) 
     588    { 
     589        if (!($node instanceof Twig_Node_Expression_Constant || $node instanceof Twig_Node_Expression_Array)) { 
     590            return false; 
     591        } 
     592 
     593        foreach ($node as $n) { 
     594            if (!$this->checkConstantExpression($n)) { 
     595                return false; 
     596            } 
     597        } 
     598 
     599        return true; 
    494600    } 
    495601} 
  • inc/libs/twig/Extension/Core.php

    r991 r1101  
    127127        $filters = array( 
    128128            // formatting filters 
    129             'date'          => new Twig_Filter_Function('twig_date_format_filter', array('needs_environment' => true)), 
    130             'date_modify'   => new Twig_Filter_Function('twig_date_modify_filter', array('needs_environment' => true)), 
    131             'format'        => new Twig_Filter_Function('sprintf'), 
    132             'replace'       => new Twig_Filter_Function('strtr'), 
    133             'number_format' => new Twig_Filter_Function('twig_number_format_filter', array('needs_environment' => true)), 
    134             'abs'           => new Twig_Filter_Function('abs'), 
     129            new Twig_SimpleFilter('date', 'twig_date_format_filter', array('needs_environment' => true)), 
     130            new Twig_SimpleFilter('date_modify', 'twig_date_modify_filter', array('needs_environment' => true)), 
     131            new Twig_SimpleFilter('format', 'sprintf'), 
     132            new Twig_SimpleFilter('replace', 'strtr'), 
     133            new Twig_SimpleFilter('number_format', 'twig_number_format_filter', array('needs_environment' => true)), 
     134            new Twig_SimpleFilter('abs', 'abs'), 
    135135 
    136136            // encoding 
    137             'url_encode'       => new Twig_Filter_Function('twig_urlencode_filter'), 
    138             'json_encode'      => new Twig_Filter_Function('twig_jsonencode_filter'), 
    139             'convert_encoding' => new Twig_Filter_Function('twig_convert_encoding'), 
     137            new Twig_SimpleFilter('url_encode', 'twig_urlencode_filter'), 
     138            new Twig_SimpleFilter('json_encode', 'twig_jsonencode_filter'), 
     139            new Twig_SimpleFilter('convert_encoding', 'twig_convert_encoding'), 
    140140 
    141141            // string filters 
    142             'title'      => new Twig_Filter_Function('twig_title_string_filter', array('needs_environment' => true)), 
    143             'capitalize' => new Twig_Filter_Function('twig_capitalize_string_filter', array('needs_environment' => true)), 
    144             'upper'      => new Twig_Filter_Function('strtoupper'), 
    145             'lower'      => new Twig_Filter_Function('strtolower'), 
    146             'striptags'  => new Twig_Filter_Function('strip_tags'), 
    147             'trim'       => new Twig_Filter_Function('trim'), 
    148             'nl2br'      => new Twig_Filter_Function('nl2br', array('pre_escape' => 'html', 'is_safe' => array('html'))), 
     142            new Twig_SimpleFilter('title', 'twig_title_string_filter', array('needs_environment' => true)), 
     143            new Twig_SimpleFilter('capitalize', 'twig_capitalize_string_filter', array('needs_environment' => true)), 
     144            new Twig_SimpleFilter('upper', 'strtoupper'), 
     145            new Twig_SimpleFilter('lower', 'strtolower'), 
     146            new Twig_SimpleFilter('striptags', 'strip_tags'), 
     147            new Twig_SimpleFilter('trim', 'trim'), 
     148            new Twig_SimpleFilter('nl2br', 'nl2br', array('pre_escape' => 'html', 'is_safe' => array('html'))), 
    149149 
    150150            // array helpers 
    151             'join'    => new Twig_Filter_Function('twig_join_filter'), 
    152             'split'   => new Twig_Filter_Function('twig_split_filter'), 
    153             'sort'    => new Twig_Filter_Function('twig_sort_filter'), 
    154             'merge'   => new Twig_Filter_Function('twig_array_merge'), 
     151            new Twig_SimpleFilter('join', 'twig_join_filter'), 
     152            new Twig_SimpleFilter('split', 'twig_split_filter'), 
     153            new Twig_SimpleFilter('sort', 'twig_sort_filter'), 
     154            new Twig_SimpleFilter('merge', 'twig_array_merge'), 
    155155 
    156156            // string/array filters 
    157             'reverse' => new Twig_Filter_Function('twig_reverse_filter', array('needs_environment' => true)), 
    158             'length'  => new Twig_Filter_Function('twig_length_filter', array('needs_environment' => true)), 
    159             'slice'   => new Twig_Filter_Function('twig_slice', array('needs_environment' => true)), 
     157            new Twig_SimpleFilter('reverse', 'twig_reverse_filter', array('needs_environment' => true)), 
     158            new Twig_SimpleFilter('length', 'twig_length_filter', array('needs_environment' => true)), 
     159            new Twig_SimpleFilter('slice', 'twig_slice', array('needs_environment' => true)), 
     160            new Twig_SimpleFilter('first', 'twig_first', array('needs_environment' => true)), 
     161            new Twig_SimpleFilter('last', 'twig_last', array('needs_environment' => true)), 
    160162 
    161163            // iteration and runtime 
    162             'default' => new Twig_Filter_Node('Twig_Node_Expression_Filter_Default'), 
    163             '_default' => new Twig_Filter_Function('_twig_default_filter'), 
    164  
    165             'keys'    => new Twig_Filter_Function('twig_get_array_keys_filter'), 
     164            new Twig_SimpleFilter('default', '_twig_default_filter', array('node_class' => 'Twig_Node_Expression_Filter_Default')), 
     165            new Twig_SimpleFilter('keys', 'twig_get_array_keys_filter'), 
    166166 
    167167            // escaping 
    168             'escape' => new Twig_Filter_Function('twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')), 
    169             'e'      => new Twig_Filter_Function('twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')), 
     168            new Twig_SimpleFilter('escape', 'twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')), 
     169            new Twig_SimpleFilter('e', 'twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')), 
    170170        ); 
    171171 
     
    186186    { 
    187187        return array( 
    188             'range'    => new Twig_Function_Function('range'), 
    189             'constant' => new Twig_Function_Function('constant'), 
    190             'cycle'    => new Twig_Function_Function('twig_cycle'), 
    191             'random'   => new Twig_Function_Function('twig_random', array('needs_environment' => true)), 
    192             'date'     => new Twig_Function_Function('twig_date_converter', array('needs_environment' => true)), 
     188            new Twig_SimpleFunction('range', 'range'), 
     189            new Twig_SimpleFunction('constant', 'twig_constant'), 
     190            new Twig_SimpleFunction('cycle', 'twig_cycle'), 
     191            new Twig_SimpleFunction('random', 'twig_random', array('needs_environment' => true)), 
     192            new Twig_SimpleFunction('date', 'twig_date_converter', array('needs_environment' => true)), 
     193            new Twig_SimpleFunction('include', 'twig_include', array('needs_environment' => true, 'needs_context' => true)), 
    193194        ); 
    194195    } 
     
    202203    { 
    203204        return array( 
    204             'even'        => new Twig_Test_Node('Twig_Node_Expression_Test_Even'), 
    205             'odd'         => new Twig_Test_Node('Twig_Node_Expression_Test_Odd'), 
    206             'defined'     => new Twig_Test_Node('Twig_Node_Expression_Test_Defined'), 
    207             'sameas'      => new Twig_Test_Node('Twig_Node_Expression_Test_Sameas'), 
    208             'none'        => new Twig_Test_Node('Twig_Node_Expression_Test_Null'), 
    209             'null'        => new Twig_Test_Node('Twig_Node_Expression_Test_Null'), 
    210             'divisibleby' => new Twig_Test_Node('Twig_Node_Expression_Test_Divisibleby'), 
    211             'constant'    => new Twig_Test_Node('Twig_Node_Expression_Test_Constant'), 
    212             'empty'       => new Twig_Test_Function('twig_test_empty'), 
    213             'iterable'    => new Twig_Test_Function('twig_test_iterable'), 
     205            new Twig_SimpleTest('even', null, array('node_class' => 'Twig_Node_Expression_Test_Even')), 
     206            new Twig_SimpleTest('odd', null, array('node_class' => 'Twig_Node_Expression_Test_Odd')), 
     207            new Twig_SimpleTest('defined', null, array('node_class' => 'Twig_Node_Expression_Test_Defined')), 
     208            new Twig_SimpleTest('sameas', null, array('node_class' => 'Twig_Node_Expression_Test_Sameas')), 
     209            new Twig_SimpleTest('none', null, array('node_class' => 'Twig_Node_Expression_Test_Null')), 
     210            new Twig_SimpleTest('null', null, array('node_class' => 'Twig_Node_Expression_Test_Null')), 
     211            new Twig_SimpleTest('divisibleby', null, array('node_class' => 'Twig_Node_Expression_Test_Divisibleby')), 
     212            new Twig_SimpleTest('constant', null, array('node_class' => 'Twig_Node_Expression_Test_Constant')), 
     213            new Twig_SimpleTest('empty', 'twig_test_empty'), 
     214            new Twig_SimpleTest('iterable', 'twig_test_iterable'), 
    214215        ); 
    215216    } 
     
    268269        $arguments = null; 
    269270        if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) { 
    270             $arguments = $parser->getExpressionParser()->parseArguments(); 
    271         } 
    272  
    273         $class = $this->getTestNodeClass($parser->getEnvironment(), $name); 
     271            $arguments = $parser->getExpressionParser()->parseArguments(true); 
     272        } 
     273 
     274        $class = $this->getTestNodeClass($parser, $name, $node->getLine()); 
    274275 
    275276        return new $class($node, $name, $arguments, $parser->getCurrentToken()->getLine()); 
    276277    } 
    277278 
    278     protected function getTestNodeClass(Twig_Environment $env, $name) 
    279     { 
     279    protected function getTestNodeClass(Twig_Parser $parser, $name, $line) 
     280    { 
     281        $env = $parser->getEnvironment(); 
    280282        $testMap = $env->getTests(); 
    281         if (isset($testMap[$name]) && $testMap[$name] instanceof Twig_Test_Node) { 
    282             return $testMap[$name]->getClass(); 
    283         } 
    284  
    285         return 'Twig_Node_Expression_Test'; 
     283        if (!isset($testMap[$name])) { 
     284            $message = sprintf('The test "%s" does not exist', $name); 
     285            if ($alternatives = $env->computeAlternatives($name, array_keys($env->getTests()))) { 
     286                $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); 
     287            } 
     288 
     289            throw new Twig_Error_Syntax($message, $line, $parser->getFilename()); 
     290        } 
     291 
     292        if ($testMap[$name] instanceof Twig_SimpleTest) { 
     293            return $testMap[$name]->getNodeClass(); 
     294        } 
     295 
     296        return $testMap[$name] instanceof Twig_Test_Node ? $testMap[$name]->getClass() : 'Twig_Node_Expression_Test'; 
    286297    } 
    287298 
     
    300311 * Cycles over a value. 
    301312 * 
    302  * @param ArrayAccess|array $values An array or an ArrayAccess instance 
    303  * @param integer           $i      The cycle value 
     313 * @param ArrayAccess|array $values   An array or an ArrayAccess instance 
     314 * @param integer           $position The cycle position 
    304315 * 
    305316 * @return string The next value in the cycle 
    306317 */ 
    307 function twig_cycle($values, $i) 
     318function twig_cycle($values, $position) 
    308319{ 
    309320    if (!is_array($values) && !$values instanceof ArrayAccess) { 
     
    311322    } 
    312323 
    313     return $values[$i % count($values)]; 
     324    return $values[$position % count($values)]; 
    314325} 
    315326 
     
    405416 * 
    406417 * <pre> 
    407  *   {{ post.published_at|modify("-1day")|date("m/d/Y") }} 
     418 *   {{ post.published_at|date_modify("-1day")|date("m/d/Y") }} 
    408419 * </pre> 
    409420 * 
     
    459470    $asString = (string) $date; 
    460471    if (ctype_digit($asString) || (!empty($asString) && '-' === $asString[0] && ctype_digit(substr($asString, 1)))) { 
    461         $date = new DateTime('@'.$date); 
     472        $date = '@'.$date; 
     473    } 
     474 
     475    $date = new DateTime($date, $defaultTimezone); 
     476    if (false !== $timezone) { 
    462477        $date->setTimezone($defaultTimezone); 
    463  
    464         return $date; 
    465     } 
    466  
    467     return new DateTime($date, $defaultTimezone); 
     478    } 
     479 
     480    return $date; 
    468481} 
    469482 
     
    621634 
    622635/** 
     636 * Returns the first element of the item. 
     637 * 
     638 * @param Twig_Environment $env  A Twig_Environment instance 
     639 * @param mixed            $item A variable 
     640 * 
     641 * @return mixed The first element of the item 
     642 */ 
     643function twig_first(Twig_Environment $env, $item) 
     644{ 
     645    $elements = twig_slice($env, $item, 0, 1, false); 
     646 
     647    return is_string($elements) ? $elements[0] : current($elements); 
     648} 
     649 
     650/** 
     651 * Returns the last element of the item. 
     652 * 
     653 * @param Twig_Environment $env  A Twig_Environment instance 
     654 * @param mixed            $item A variable 
     655 * 
     656 * @return mixed The last element of the item 
     657 */ 
     658function twig_last(Twig_Environment $env, $item) 
     659{ 
     660    $elements = twig_slice($env, $item, -1, 1, false); 
     661 
     662    return is_string($elements) ? $elements[0] : current($elements); 
     663} 
     664 
     665/** 
    623666 * Joins the values to a string. 
    624667 * 
     
    774817function twig_in_filter($value, $compare) 
    775818{ 
    776     $strict = is_object($value); 
    777  
    778819    if (is_array($compare)) { 
    779         return in_array($value, $compare, $strict); 
     820        return in_array($value, $compare, is_object($value)); 
    780821    } elseif (is_string($compare)) { 
    781         if (!strlen((string) $value)) { 
     822        if (!strlen($value)) { 
    782823            return empty($compare); 
    783824        } 
    784825 
    785826        return false !== strpos($compare, (string) $value); 
    786     } elseif (is_object($compare) && $compare instanceof Traversable) { 
    787         return in_array($value, iterator_to_array($compare, false), $strict); 
     827    } elseif ($compare instanceof Traversable) { 
     828        return in_array($value, iterator_to_array($compare, false), is_object($value)); 
    788829    } 
    789830 
     
    11921233    } 
    11931234 
    1194     return false === $value || (empty($value) && '0' != $value); 
     1235    return '' === $value || false === $value || null === $value || array() === $value; 
    11951236} 
    11961237 
     
    12131254    return $value instanceof Traversable || is_array($value); 
    12141255} 
     1256 
     1257/** 
     1258 * Renders a template. 
     1259 * 
     1260 * @param string  template       The template to render 
     1261 * @param array   variables      The variables to pass to the template 
     1262 * @param Boolean with_context   Whether to pass the current context variables or not 
     1263 * @param Boolean ignore_missing Whether to ignore missing templates or not 
     1264 * @param Boolean sandboxed      Whether to sandbox the template or not 
     1265 * 
     1266 * @return string The rendered template 
     1267 */ 
     1268function twig_include(Twig_Environment $env, $context, $template, $variables = array(), $withContext = true, $ignoreMissing = false, $sandboxed = false) 
     1269{ 
     1270    if ($withContext) { 
     1271        $variables = array_merge($context, $variables); 
     1272    } 
     1273 
     1274    if ($isSandboxed = $sandboxed && $env->hasExtension('sandbox')) { 
     1275        $sandbox = $env->getExtension('sandbox'); 
     1276        if (!$alreadySandboxed = $sandbox->isSandboxed()) { 
     1277            $sandbox->enableSandbox(); 
     1278        } 
     1279    } 
     1280 
     1281    try { 
     1282        return $env->resolveTemplate($template)->display($variables); 
     1283    } catch (Twig_Error_Loader $e) { 
     1284        if (!$ignoreMissing) { 
     1285            throw $e; 
     1286        } 
     1287    } 
     1288 
     1289    if ($isSandboxed && !$alreadySandboxed) { 
     1290        $sandbox->disableSandbox(); 
     1291    } 
     1292} 
     1293 
     1294/** 
     1295 * Provides the ability to get constants from instances as well as class/global constants. 
     1296 * 
     1297 * @param string      $constant The name of the constant 
     1298 * @param null|object $object   The object to get the constant from 
     1299 * 
     1300 * @return string 
     1301 */ 
     1302function twig_constant($constant, $object = null) 
     1303{ 
     1304    if (null !== $object) { 
     1305        $constant = get_class($object).'::'.$constant; 
     1306    } 
     1307 
     1308    return constant($constant); 
     1309} 
  • inc/libs/twig/Extension/Debug.php

    r991 r1101  
    2828 
    2929        return array( 
    30             'dump' => new Twig_Function_Function('twig_var_dump', array('is_safe' => $isDumpOutputHtmlSafe ? array('html') : array(), 'needs_context' => true, 'needs_environment' => true)), 
     30            new Twig_SimpleFunction('dump', 'twig_var_dump', array('is_safe' => $isDumpOutputHtmlSafe ? array('html') : array(), 'needs_context' => true, 'needs_environment' => true)), 
    3131        ); 
    3232    } 
  • inc/libs/twig/Extension/Escaper.php

    r991 r1101  
    4646    { 
    4747        return array( 
    48             'raw' => new Twig_Filter_Function('twig_raw_filter', array('is_safe' => array('all'))), 
     48            new Twig_SimpleFilter('raw', 'twig_raw_filter', array('is_safe' => array('all'))), 
    4949        ); 
    5050    } 
  • inc/libs/twig/Extension/StringLoader.php

    r991 r1101  
    1717    { 
    1818        return array( 
    19             'template_from_string' => new Twig_Function_Function('twig_template_from_string', array('needs_environment' => true)), 
     19            new Twig_SimpleFunction('template_from_string', 'twig_template_from_string', array('needs_environment' => true)), 
    2020        ); 
    2121    } 
  • inc/libs/twig/Filter.php

    r991 r1101  
    1313 * Represents a template filter. 
    1414 * 
     15 * Use Twig_SimpleFilter instead. 
     16 * 
    1517 * @package    twig 
    1618 * @author     Fabien Potencier <fabien@symfony.com> 
     19 * @deprecated since 1.12 (to be removed in 2.0) 
    1720 */ 
    18 abstract class Twig_Filter implements Twig_FilterInterface 
     21abstract class Twig_Filter implements Twig_FilterInterface, Twig_FilterCallableInterface 
    1922{ 
    2023    protected $options; 
     
    2831            'pre_escape'        => null, 
    2932            'preserves_safety'  => null, 
     33            'callable'          => null, 
    3034        ), $options); 
    3135    } 
     
    7377        return $this->options['pre_escape']; 
    7478    } 
     79 
     80    public function getCallable() 
     81    { 
     82        return $this->options['callable']; 
     83    } 
    7584} 
  • inc/libs/twig/Filter/Function.php

    r991 r1101  
    1313 * Represents a function template filter. 
    1414 * 
     15 * Use Twig_SimpleFilter instead. 
     16 * 
    1517 * @package    twig 
    1618 * @author     Fabien Potencier <fabien@symfony.com> 
     19 * @deprecated since 1.12 (to be removed in 2.0) 
    1720 */ 
    1821class Twig_Filter_Function extends Twig_Filter 
     
    2225    public function __construct($function, array $options = array()) 
    2326    { 
     27        $options['callable'] = $function; 
     28 
    2429        parent::__construct($options); 
    2530 
  • inc/libs/twig/Filter/Method.php

    r991 r1101  
    1313 * Represents a method template filter. 
    1414 * 
     15 * Use Twig_SimpleFilter instead. 
     16 * 
    1517 * @package    twig 
    1618 * @author     Fabien Potencier <fabien@symfony.com> 
     19 * @deprecated since 1.12 (to be removed in 2.0) 
    1720 */ 
    1821class Twig_Filter_Method extends Twig_Filter 
     
    2326    public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array()) 
    2427    { 
     28        $options['callable'] = array($extension, $method); 
     29 
    2530        parent::__construct($options); 
    2631 
  • inc/libs/twig/Filter/Node.php

    r991 r1101  
    1313 * Represents a template filter as a node. 
    1414 * 
     15 * Use Twig_SimpleFilter instead. 
     16 * 
    1517 * @package    twig 
    1618 * @author     Fabien Potencier <fabien@symfony.com> 
     19 * @deprecated since 1.12 (to be removed in 2.0) 
    1720 */ 
    1821class Twig_Filter_Node extends Twig_Filter 
  • inc/libs/twig/FilterInterface.php

    r991 r1101  
    1313 * Represents a template filter. 
    1414 * 
     15 * Use Twig_SimpleFilter instead. 
     16 * 
    1517 * @package    twig 
    1618 * @author     Fabien Potencier <fabien@symfony.com> 
     19 * @deprecated since 1.12 (to be removed in 2.0) 
    1720 */ 
    1821interface Twig_FilterInterface 
  • inc/libs/twig/Function.php

    r991 r1101  
    1313 * Represents a template function. 
    1414 * 
     15 * Use Twig_SimpleFunction instead. 
     16 * 
    1517 * @package    twig 
    1618 * @author     Fabien Potencier <fabien@symfony.com> 
     19 * @deprecated since 1.12 (to be removed in 2.0) 
    1720 */ 
    18 abstract class Twig_Function implements Twig_FunctionInterface 
     21abstract class Twig_Function implements Twig_FunctionInterface, Twig_FunctionCallableInterface 
    1922{ 
    2023    protected $options; 
     
    2629            'needs_environment' => false, 
    2730            'needs_context'     => false, 
     31            'callable'          => null, 
    2832        ), $options); 
    2933    } 
     
    6165        return array(); 
    6266    } 
     67 
     68    public function getCallable() 
     69    { 
     70        return $this->options['callable']; 
     71    } 
    6372} 
  • inc/libs/twig/Function/Function.php

    r0 r1101  
    1414 * Represents a function template function. 
    1515 * 
     16 * Use Twig_SimpleFunction instead. 
     17 * 
    1618 * @package    twig 
    1719 * @author     Arnaud Le Blanc <arnaud.lb@gmail.com> 
     20 * @deprecated since 1.12 (to be removed in 2.0) 
    1821 */ 
    1922class Twig_Function_Function extends Twig_Function 
     
    2326    public function __construct($function, array $options = array()) 
    2427    { 
     28        $options['callable'] = $function; 
     29 
    2530        parent::__construct($options); 
    2631 
  • inc/libs/twig/Function/Method.php

    r991 r1101  
    1414 * Represents a method template function. 
    1515 * 
     16 * Use Twig_SimpleFunction instead. 
     17 * 
    1618 * @package    twig 
    1719 * @author     Arnaud Le Blanc <arnaud.lb@gmail.com> 
     20 * @deprecated since 1.12 (to be removed in 2.0) 
    1821 */ 
    1922class Twig_Function_Method extends Twig_Function 
     
    2427    public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array()) 
    2528    { 
     29        $options['callable'] = array($extension, $method); 
     30 
    2631        parent::__construct($options); 
    2732 
  • inc/libs/twig/Function/Node.php

    r991 r1101  
    1313 * Represents a template function as a node. 
    1414 * 
     15 * Use Twig_SimpleFunction instead. 
     16 * 
    1517 * @package    twig 
    1618 * @author     Fabien Potencier <fabien@symfony.com> 
     19 * @deprecated since 1.12 (to be removed in 2.0) 
    1720 */ 
    1821class Twig_Function_Node extends Twig_Function 
  • inc/libs/twig/FunctionInterface.php

    r991 r1101  
    1414 * Represents a template function. 
    1515 * 
     16 * Use Twig_SimpleFunction instead. 
     17 * 
    1618 * @package    twig 
    1719 * @author     Arnaud Le Blanc <arnaud.lb@gmail.com> 
     20 * @deprecated since 1.12 (to be removed in 2.0) 
    1821 */ 
    1922interface Twig_FunctionInterface 
  • inc/libs/twig/LICENSE

    r0 r1101  
    1 Copyright (c) 2009 by the Twig Team, see AUTHORS for more details. 
     1Copyright (c) 2009-2013 by the Twig Team, see AUTHORS for more details. 
    22 
    33Some rights reserved. 
  • inc/libs/twig/Lexer.php

    r991 r1101  
    6262            'lex_var'             => '/\s*'.preg_quote($this->options['whitespace_trim'].$this->options['tag_variable'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_variable'][1], '/').'/A', 
    6363            'lex_block'           => '/\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')\n?/A', 
    64             'lex_raw_data'        => '/('.preg_quote($this->options['tag_block'][0].$this->options['whitespace_trim'], '/').'|'.preg_quote($this->options['tag_block'][0], '/').')\s*endraw\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/s', 
     64            'lex_raw_data'        => '/('.preg_quote($this->options['tag_block'][0].$this->options['whitespace_trim'], '/').'|'.preg_quote($this->options['tag_block'][0], '/').')\s*(?:end%s)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/s', 
    6565            'operator'            => $this->getOperatorRegex(), 
    6666            'lex_comment'         => '/(?:'.preg_quote($this->options['whitespace_trim'], '/').preg_quote($this->options['tag_comment'][1], '/').'\s*|'.preg_quote($this->options['tag_comment'][1], '/').')\n?/s', 
    67             'lex_block_raw'       => '/\s*raw\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/As', 
     67            'lex_block_raw'       => '/\s*(raw|verbatim)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/As', 
    6868            'lex_block_line'      => '/\s*line\s+(\d+)\s*'.preg_quote($this->options['tag_block'][1], '/').'/As', 
    6969            'lex_tokens_start'    => '/('.preg_quote($this->options['tag_variable'][0], '/').'|'.preg_quote($this->options['tag_block'][0], '/').'|'.preg_quote($this->options['tag_comment'][0], '/').')('.preg_quote($this->options['whitespace_trim'], '/').')?/s', 
     
    179179                if (preg_match($this->regexes['lex_block_raw'], $this->code, $match, null, $this->cursor)) { 
    180180                    $this->moveCursor($match[0]); 
    181                     $this->lexRawData(); 
     181                    $this->lexRawData($match[1]); 
    182182                // {% line \d+ %} 
    183183                } elseif (preg_match($this->regexes['lex_block_line'], $this->code, $match, null, $this->cursor)) { 
     
    287287    } 
    288288 
    289     protected function lexRawData() 
    290     { 
    291         if (!preg_match($this->regexes['lex_raw_data'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) { 
    292             throw new Twig_Error_Syntax(sprintf('Unexpected end of file: Unclosed "block"'), $this->lineno, $this->filename); 
     289    protected function lexRawData($tag) 
     290    { 
     291        if (!preg_match(str_replace('%s', $tag, $this->regexes['lex_raw_data']), $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) { 
     292            throw new Twig_Error_Syntax(sprintf('Unexpected end of file: Unclosed "%s" block', $tag), $this->lineno, $this->filename); 
    293293        } 
    294294 
  • inc/libs/twig/LexerInterface.php

    r991 r1101  
    1515 * @package    twig 
    1616 * @author     Fabien Potencier <fabien@symfony.com> 
     17 * @deprecated since 1.12 (to be removed in 2.0) 
    1718 */ 
    1819interface Twig_LexerInterface 
  • inc/libs/twig/Node/Expression/Filter.php

    r991 r1101  
    1010 * file that was distributed with this source code. 
    1111 */ 
    12 class Twig_Node_Expression_Filter extends Twig_Node_Expression 
     12class Twig_Node_Expression_Filter extends Twig_Node_Expression_Call 
    1313{ 
    1414    public function __construct(Twig_NodeInterface $node, Twig_Node_Expression_Constant $filterName, Twig_NodeInterface $arguments, $lineno, $tag = null) 
     
    2020    { 
    2121        $name = $this->getNode('filter')->getAttribute('value'); 
     22        $filter = $compiler->getEnvironment()->getFilter($name); 
    2223 
    23         if (false === $filter = $compiler->getEnvironment()->getFilter($name)) { 
    24             $message = sprintf('The filter "%s" does not exist', $name); 
    25             if ($alternatives = $compiler->getEnvironment()->computeAlternatives($name, array_keys($compiler->getEnvironment()->getFilters()))) { 
    26                 $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); 
    27             } 
    28  
    29             throw new Twig_Error_Syntax($message, $this->getLine(), $compiler->getFilename()); 
     24        $this->setAttribute('name', $name); 
     25        $this->setAttribute('type', 'filter'); 
     26        $this->setAttribute('thing', $filter); 
     27        $this->setAttribute('needs_environment', $filter->needsEnvironment()); 
     28        $this->setAttribute('needs_context', $filter->needsContext()); 
     29        $this->setAttribute('arguments', $filter->getArguments()); 
     30        if ($filter instanceof Twig_FilterCallableInterface || $filter instanceof Twig_SimpleFilter) { 
     31            $this->setAttribute('callable', $filter->getCallable()); 
    3032        } 
    3133 
    32         $this->compileFilter($compiler, $filter); 
    33     } 
    34  
    35     protected function compileFilter(Twig_Compiler $compiler, Twig_FilterInterface $filter) 
    36     { 
    37         $compiler 
    38             ->raw($filter->compile().'(') 
    39             ->raw($filter->needsEnvironment() ? '$this->env, ' : '') 
    40             ->raw($filter->needsContext() ? '$context, ' : '') 
    41         ; 
    42  
    43         foreach ($filter->getArguments() as $argument) { 
    44             $compiler 
    45                 ->string($argument) 
    46                 ->raw(', ') 
    47             ; 
    48         } 
    49  
    50         $compiler->subcompile($this->getNode('node')); 
    51  
    52         foreach ($this->getNode('arguments') as $node) { 
    53             $compiler 
    54                 ->raw(', ') 
    55                 ->subcompile($node) 
    56             ; 
    57         } 
    58  
    59         $compiler->raw(')'); 
     34        $this->compileCallable($compiler); 
    6035    } 
    6136} 
  • inc/libs/twig/Node/Expression/Filter/Default.php

    r991 r1101  
    2424    public function __construct(Twig_NodeInterface $node, Twig_Node_Expression_Constant $filterName, Twig_NodeInterface $arguments, $lineno, $tag = null) 
    2525    { 
    26         $default = new Twig_Node_Expression_Filter($node, new Twig_Node_Expression_Constant('_default', $node->getLine()), $arguments, $node->getLine()); 
     26        $default = new Twig_Node_Expression_Filter($node, new Twig_Node_Expression_Constant('default', $node->getLine()), $arguments, $node->getLine()); 
    2727 
    2828        if ('default' === $filterName->getAttribute('value') && ($node instanceof Twig_Node_Expression_Name || $node instanceof Twig_Node_Expression_GetAttr)) { 
  • inc/libs/twig/Node/Expression/Function.php

    r991 r1101  
    99 * file that was distributed with this source code. 
    1010 */ 
    11 class Twig_Node_Expression_Function extends Twig_Node_Expression 
     11class Twig_Node_Expression_Function extends Twig_Node_Expression_Call 
    1212{ 
    1313    public function __construct($name, Twig_NodeInterface $arguments, $lineno) 
     
    1919    { 
    2020        $name = $this->getAttribute('name'); 
     21        $function = $compiler->getEnvironment()->getFunction($name); 
    2122 
    22         if (false === $function = $compiler->getEnvironment()->getFunction($name)) { 
    23             $message = sprintf('The function "%s" does not exist', $name); 
    24             if ($alternatives = $compiler->getEnvironment()->computeAlternatives($name, array_keys($compiler->getEnvironment()->getFunctions()))) { 
    25                 $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); 
    26             } 
    27  
    28             throw new Twig_Error_Syntax($message, $this->getLine(), $compiler->getFilename()); 
     23        $this->setAttribute('name', $name); 
     24        $this->setAttribute('type', 'function'); 
     25        $this->setAttribute('thing', $function); 
     26        $this->setAttribute('needs_environment', $function->needsEnvironment()); 
     27        $this->setAttribute('needs_context', $function->needsContext()); 
     28        $this->setAttribute('arguments', $function->getArguments()); 
     29        if ($function instanceof Twig_FunctionCallableInterface || $function instanceof Twig_SimpleFunction) { 
     30            $this->setAttribute('callable', $function->getCallable()); 
    2931        } 
    3032 
    31         $compiler->raw($function->compile().'('); 
    32  
    33         $first = true; 
    34  
    35         if ($function->needsEnvironment()) { 
    36             $compiler->raw('$this->env'); 
    37             $first = false; 
    38         } 
    39  
    40         if ($function->needsContext()) { 
    41             if (!$first) { 
    42                 $compiler->raw(', '); 
    43             } 
    44             $compiler->raw('$context'); 
    45             $first = false; 
    46         } 
    47  
    48         foreach ($function->getArguments() as $argument) { 
    49             if (!$first) { 
    50                 $compiler->raw(', '); 
    51             } 
    52             $compiler->string($argument); 
    53             $first = false; 
    54         } 
    55  
    56         foreach ($this->getNode('arguments') as $node) { 
    57             if (!$first) { 
    58                 $compiler->raw(', '); 
    59             } 
    60             $compiler->subcompile($node); 
    61             $first = false; 
    62         } 
    63  
    64         $compiler->raw(')'); 
     33        $this->compileCallable($compiler); 
    6534    } 
    6635} 
  • inc/libs/twig/Node/Expression/Test.php

    r991 r1101  
    99 * file that was distributed with this source code. 
    1010 */ 
    11 class Twig_Node_Expression_Test extends Twig_Node_Expression 
     11class Twig_Node_Expression_Test extends Twig_Node_Expression_Call 
    1212{ 
    1313    public function __construct(Twig_NodeInterface $node, $name, Twig_NodeInterface $arguments = null, $lineno) 
     
    1919    { 
    2020        $name = $this->getAttribute('name'); 
    21         $testMap = $compiler->getEnvironment()->getTests(); 
    22         if (!isset($testMap[$name])) { 
    23             $message = sprintf('The test "%s" does not exist', $name); 
    24             if ($alternatives = $compiler->getEnvironment()->computeAlternatives($name, array_keys($compiler->getEnvironment()->getTests()))) { 
    25                 $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); 
    26             } 
     21        $test = $compiler->getEnvironment()->getTest($name); 
    2722 
    28             throw new Twig_Error_Syntax($message, $this->getLine(), $compiler->getFilename()); 
     23        $this->setAttribute('name', $name); 
     24        $this->setAttribute('type', 'test'); 
     25        $this->setAttribute('thing', $test); 
     26        if ($test instanceof Twig_TestCallableInterface || $test instanceof Twig_SimpleTest) { 
     27            $this->setAttribute('callable', $test->getCallable()); 
    2928        } 
    3029 
    31         $name = $this->getAttribute('name'); 
    32         $node = $this->getNode('node'); 
    33  
    34         $compiler 
    35             ->raw($testMap[$name]->compile().'(') 
    36             ->subcompile($node) 
    37         ; 
    38  
    39         if (null !== $this->getNode('arguments')) { 
    40             $compiler->raw(', '); 
    41  
    42             $max = count($this->getNode('arguments')) - 1; 
    43             foreach ($this->getNode('arguments') as $i => $arg) { 
    44                 $compiler->subcompile($arg); 
    45  
    46                 if ($i != $max) { 
    47                     $compiler->raw(', '); 
    48                 } 
    49             } 
    50         } 
    51  
    52         $compiler->raw(')'); 
     30        $this->compileCallable($compiler); 
    5331    } 
    5432} 
  • inc/libs/twig/Node/Macro.php

    r991 r1101  
    3030    public function compile(Twig_Compiler $compiler) 
    3131    { 
    32         $arguments = array(); 
    33         foreach ($this->getNode('arguments') as $argument) { 
    34             $arguments[] = '$_'.$argument->getAttribute('name').' = null'; 
     32        $compiler 
     33            ->addDebugInfo($this) 
     34            ->write(sprintf("public function get%s(", $this->getAttribute('name'))) 
     35        ; 
     36 
     37        $count = count($this->getNode('arguments')); 
     38        $pos = 0; 
     39        foreach ($this->getNode('arguments') as $name => $default) { 
     40            $compiler 
     41                ->raw('$_'.$name.' = ') 
     42                ->subcompile($default) 
     43            ; 
     44 
     45            if (++$pos < $count) { 
     46                $compiler->raw(', '); 
     47            } 
    3548        } 
    3649 
    3750        $compiler 
    38             ->addDebugInfo($this) 
    39             ->write(sprintf("public function get%s(%s)\n", $this->getAttribute('name'), implode(', ', $arguments)), "{\n") 
     51            ->raw(")\n") 
     52            ->write("{\n") 
    4053            ->indent() 
    4154        ; 
     
    4962            ; 
    5063 
    51             foreach ($this->getNode('arguments') as $argument) { 
     64            foreach ($this->getNode('arguments') as $name => $default) { 
    5265                $compiler 
    5366                    ->write('') 
    54                     ->string($argument->getAttribute('name')) 
    55                     ->raw(' => $_'.$argument->getAttribute('name')) 
     67                    ->string($name) 
     68                    ->raw(' => $_'.$name) 
    5669                    ->raw(",\n") 
    5770                ; 
  • inc/libs/twig/NodeInterface.php

    r991 r1101  
    1515 * @package    twig 
    1616 * @author     Fabien Potencier <fabien@symfony.com> 
     17 * @deprecated since 1.12 (to be removed in 2.0) 
    1718 */ 
    1819interface Twig_NodeInterface extends Countable, IteratorAggregate 
  • inc/libs/twig/NodeVisitor/Escaper.php

    r991 r1101  
    108108        $name = $filter->getNode('filter')->getAttribute('value'); 
    109109 
    110         if (false !== $f = $env->getFilter($name)) { 
    111             $type = $f->getPreEscape(); 
    112             if (null === $type) { 
    113                 return $filter; 
    114             } 
    115  
    116             $node = $filter->getNode('node'); 
    117             if ($this->isSafeFor($type, $node, $env)) { 
    118                 return $filter; 
    119             } 
    120  
    121             $filter->setNode('node', $this->getEscaperFilter($type, $node)); 
    122  
     110        $type = $env->getFilter($name)->getPreEscape(); 
     111        if (null === $type) { 
    123112            return $filter; 
    124113        } 
     114 
     115        $node = $filter->getNode('node'); 
     116        if ($this->isSafeFor($type, $node, $env)) { 
     117            return $filter; 
     118        } 
     119 
     120        $filter->setNode('node', $this->getEscaperFilter($type, $node)); 
    125121 
    126122        return $filter; 
  • inc/libs/twig/ParserInterface.php

    r991 r1101  
    1313 * Interface implemented by parser classes. 
    1414 * 
    15  * @package twig 
    16  * @author  Fabien Potencier <fabien@symfony.com> 
     15 * @package    twig 
     16 * @author     Fabien Potencier <fabien@symfony.com> 
     17 * @deprecated since 1.12 (to be removed in 2.0) 
    1718 */ 
    1819interface Twig_ParserInterface 
  • inc/libs/twig/TemplateInterface.php

    r991 r1101  
    1313 * Interface implemented by all compiled templates. 
    1414 * 
    15  * @package twig 
    16  * @author  Fabien Potencier <fabien@symfony.com> 
     15 * @package    twig 
     16 * @author     Fabien Potencier <fabien@symfony.com> 
     17 * @deprecated since 1.12 (to be removed in 2.0) 
    1718 */ 
    1819interface Twig_TemplateInterface 
  • inc/libs/twig/Test/Function.php

    r991 r1101  
    1515 * @package    twig 
    1616 * @author     Fabien Potencier <fabien@symfony.com> 
     17 * @deprecated since 1.12 (to be removed in 2.0) 
    1718 */ 
    18 class Twig_Test_Function implements Twig_TestInterface 
     19class Twig_Test_Function extends Twig_Test 
    1920{ 
    2021    protected $function; 
    2122 
    22     public function __construct($function) 
     23    public function __construct($function, array $options = array()) 
    2324    { 
     25        $options['callable'] = $function; 
     26 
     27        parent::__construct($options); 
     28 
    2429        $this->function = $function; 
    2530    } 
  • inc/libs/twig/Test/Method.php

    r991 r1101  
    1515 * @package    twig 
    1616 * @author     Fabien Potencier <fabien@symfony.com> 
     17 * @deprecated since 1.12 (to be removed in 2.0) 
    1718 */ 
    18 class Twig_Test_Method implements Twig_TestInterface 
     19class Twig_Test_Method extends Twig_Test 
    1920{ 
    2021    protected $extension; 
    2122    protected $method; 
    2223 
    23     public function __construct(Twig_ExtensionInterface $extension, $method) 
     24    public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array()) 
    2425    { 
     26        $options['callable'] = array($extension, $method); 
     27 
     28        parent::__construct($options); 
     29 
    2530        $this->extension = $extension; 
    2631        $this->method = $method; 
  • inc/libs/twig/Test/Node.php

    r991 r1101  
    1515 * @package    twig 
    1616 * @author     Fabien Potencier <fabien@symfony.com> 
     17 * @deprecated since 1.12 (to be removed in 2.0) 
    1718 */ 
    18 class Twig_Test_Node implements Twig_TestInterface 
     19class Twig_Test_Node extends Twig_Test 
    1920{ 
    2021    protected $class; 
    2122 
    22     public function __construct($class) 
     23    public function __construct($class, array $options = array()) 
    2324    { 
     25        parent::__construct($options); 
     26 
    2427        $this->class = $class; 
    2528    } 
  • inc/libs/twig/TestInterface.php

    r991 r1101  
    1515 * @package    twig 
    1616 * @author     Fabien Potencier <fabien@symfony.com> 
     17 * @deprecated since 1.12 (to be removed in 2.0) 
    1718 */ 
    1819interface Twig_TestInterface 
  • inc/libs/twig/TokenParser/For.php

    r991 r1101  
    3434    { 
    3535        $lineno = $token->getLine(); 
     36        $stream = $this->parser->getStream(); 
    3637        $targets = $this->parser->getExpressionParser()->parseAssignmentExpression(); 
    37         $this->parser->getStream()->expect(Twig_Token::OPERATOR_TYPE, 'in'); 
     38        $stream->expect(Twig_Token::OPERATOR_TYPE, 'in'); 
    3839        $seq = $this->parser->getExpressionParser()->parseExpression(); 
    3940 
    4041        $ifexpr = null; 
    41         if ($this->parser->getStream()->test(Twig_Token::NAME_TYPE, 'if')) { 
    42             $this->parser->getStream()->next(); 
     42        if ($stream->test(Twig_Token::NAME_TYPE, 'if')) { 
     43            $stream->next(); 
    4344            $ifexpr = $this->parser->getExpressionParser()->parseExpression(); 
    4445        } 
    4546 
    46         $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); 
     47        $stream->expect(Twig_Token::BLOCK_END_TYPE); 
    4748        $body = $this->parser->subparse(array($this, 'decideForFork')); 
    48         if ($this->parser->getStream()->next()->getValue() == 'else') { 
    49             $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); 
     49        if ($stream->next()->getValue() == 'else') { 
     50            $stream->expect(Twig_Token::BLOCK_END_TYPE); 
    5051            $else = $this->parser->subparse(array($this, 'decideForEnd'), true); 
    5152        } else { 
    5253            $else = null; 
    5354        } 
    54         $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); 
     55        $stream->expect(Twig_Token::BLOCK_END_TYPE); 
    5556 
    5657        if (count($targets) > 1) { 
     
    6364            $valueTarget = $targets->getNode(0); 
    6465            $valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getLine()); 
     66        } 
     67 
     68        if ($ifexpr) { 
     69            $this->checkLoopUsageCondition($stream, $ifexpr); 
     70            $this->checkLoopUsageBody($stream, $body); 
    6571        } 
    6672 
     
    7884    } 
    7985 
     86    // the loop variable cannot be used in the condition 
     87    protected function checkLoopUsageCondition(Twig_TokenStream $stream, Twig_NodeInterface $node) 
     88    { 
     89        if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) { 
     90            throw new Twig_Error_Syntax('The "loop" variable cannot be used in a looping condition', $node->getLine(), $stream->getFilename()); 
     91        } 
     92 
     93        foreach ($node as $n) { 
     94            if (!$n) { 
     95                continue; 
     96            } 
     97 
     98            $this->checkLoopUsageCondition($stream, $n); 
     99        } 
     100    } 
     101 
     102    // check usage of non-defined loop-items 
     103    // it does not catch all problems (for instance when a for is included into another or when the variable is used in an include) 
     104    protected function checkLoopUsageBody(Twig_TokenStream $stream, Twig_NodeInterface $node) 
     105    { 
     106        if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) { 
     107            $attribute = $node->getNode('attribute'); 
     108            if ($attribute instanceof Twig_Node_Expression_Constant && in_array($attribute->getAttribute('value'), array('length', 'revindex0', 'revindex', 'last'))) { 
     109                throw new Twig_Error_Syntax(sprintf('The "loop.%s" variable is not defined when looping with a condition', $attribute->getAttribute('value')), $node->getLine(), $stream->getFilename()); 
     110            } 
     111        } 
     112 
     113        // should check for parent.loop.XXX usage 
     114        if ($node instanceof Twig_Node_For) { 
     115            return; 
     116        } 
     117 
     118        foreach ($node as $n) { 
     119            if (!$n) { 
     120                continue; 
     121            } 
     122 
     123            $this->checkLoopUsageBody($stream, $n); 
     124        } 
     125    } 
     126 
    80127    /** 
    81128     * Gets the tag name associated with this token parser. 
  • inc/libs/twig/TokenParser/Macro.php

    r991 r1101  
    3434        $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); 
    3535 
    36         $arguments = $this->parser->getExpressionParser()->parseArguments(); 
     36        $arguments = $this->parser->getExpressionParser()->parseArguments(true, true); 
    3737 
    3838        $stream->expect(Twig_Token::BLOCK_END_TYPE); 
  • inc/libs/twig/TokenParserBroker.php

    r991 r1101  
    1414 * Default implementation of a token parser broker. 
    1515 * 
    16  * @package twig 
    17  * @author  Arnaud Le Blanc <arnaud.lb@gmail.com> 
     16 * @package    twig 
     17 * @author     Arnaud Le Blanc <arnaud.lb@gmail.com> 
     18 * @deprecated since 1.12 (to be removed in 2.0) 
    1819 */ 
    1920class Twig_TokenParserBroker implements Twig_TokenParserBrokerInterface 
     
    5657 
    5758    /** 
     59     * Removes a TokenParser. 
     60     * 
     61     * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance 
     62     */ 
     63    public function removeTokenParser(Twig_TokenParserInterface $parser) 
     64    { 
     65        $name = $parser->getTag(); 
     66        if (isset($this->parsers[$name]) && $parser === $this->parsers[$name]) { 
     67            unset($this->parsers[$name]); 
     68        } 
     69    } 
     70 
     71    /** 
    5872     * Adds a TokenParserBroker. 
    5973     * 
     
    6377    { 
    6478        $this->brokers[] = $broker; 
     79    } 
     80 
     81    /** 
     82     * Removes a TokenParserBroker. 
     83     * 
     84     * @param Twig_TokenParserBroker $broker A Twig_TokenParserBroker instance 
     85     */ 
     86    public function removeTokenParserBroker(Twig_TokenParserBroker $broker) 
     87    { 
     88        if (false !== $pos = array_search($broker, $this->brokers)) { 
     89            unset($this->brokers[$pos]); 
     90        } 
    6591    } 
    6692 
  • inc/libs/twig/TokenParserBrokerInterface.php

    r991 r1101  
    1616 * Token parser brokers allows to implement custom logic in the process of resolving a token parser for a given tag name. 
    1717 * 
    18  * @package twig 
    19  * @author  Arnaud Le Blanc <arnaud.lb@gmail.com> 
     18 * @package    twig 
     19 * @author     Arnaud Le Blanc <arnaud.lb@gmail.com> 
     20 * @deprecated since 1.12 (to be removed in 2.0) 
    2021 */ 
    2122interface Twig_TokenParserBrokerInterface 
  • inc/libs/twig/TokenStream.php

    r991 r1101  
    5959    { 
    6060        if (!isset($this->tokens[++$this->current])) { 
    61             throw new Twig_Error_Syntax('Unexpected end of template', $this->token[$this->current - 1]->getLine(), $this->filename); 
     61            throw new Twig_Error_Syntax('Unexpected end of template', $this->tokens[$this->current - 1]->getLine(), $this->filename); 
    6262        } 
    6363 
     
    9898    { 
    9999        if (!isset($this->tokens[$this->current + $number])) { 
    100             throw new Twig_Error_Syntax('Unexpected end of template', $this->token[$this->current + $number - 1]->getLine(), $this->filename); 
     100            throw new Twig_Error_Syntax('Unexpected end of template', $this->tokens[$this->current + $number - 1]->getLine(), $this->filename); 
    101101        } 
    102102 
Note: See TracChangeset for help on using the changeset viewer.

Sites map