2011-10-05 06:22:53 +02:00
< ? php
/*
* This file is part of Twig .
*
2018-05-10 12:24:53 +02:00
* ( c ) Fabien Potencier
2011-10-05 06:22:53 +02:00
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
/**
* Stores the Twig configuration .
*
2013-08-01 21:20:12 +02:00
* @ author Fabien Potencier < fabien @ symfony . com >
2011-10-05 06:22:53 +02:00
*/
class Twig_Environment
{
2018-05-10 12:24:53 +02:00
const VERSION = '1.35.4-DEV' ;
const VERSION_ID = 13504 ;
const MAJOR_VERSION = 1 ;
const MINOR_VERSION = 35 ;
const RELEASE_VERSION = 4 ;
const EXTRA_VERSION = 'DEV' ;
2011-10-05 06:22:53 +02:00
protected $charset ;
protected $loader ;
protected $debug ;
protected $autoReload ;
protected $cache ;
protected $lexer ;
protected $parser ;
protected $compiler ;
protected $baseTemplateClass ;
protected $extensions ;
protected $parsers ;
protected $visitors ;
protected $filters ;
protected $tests ;
protected $functions ;
protected $globals ;
2018-05-10 12:24:53 +02:00
protected $runtimeInitialized = false ;
protected $extensionInitialized = false ;
2011-10-05 06:22:53 +02:00
protected $loadedTemplates ;
protected $strictVariables ;
protected $unaryOperators ;
protected $binaryOperators ;
protected $templateClassPrefix = '__TwigTemplate_' ;
2018-05-10 12:24:53 +02:00
protected $functionCallbacks = array ();
protected $filterCallbacks = array ();
2013-08-01 21:20:12 +02:00
protected $staging ;
2018-05-10 12:24:53 +02:00
private $originalCache ;
private $bcWriteCacheFile = false ;
private $bcGetCacheFilename = false ;
private $lastModifiedExtension = 0 ;
private $extensionsByClass = array ();
private $runtimeLoaders = array ();
private $runtimes = array ();
private $optionsHash ;
private $loading = array ();
2011-10-05 06:22:53 +02:00
/**
* Constructor .
*
* Available options :
*
2013-08-01 21:20:12 +02:00
* * debug : When set to true , it automatically set " auto_reload " to true as
* well ( default to false ) .
2011-10-05 06:22:53 +02:00
*
2013-08-01 21:20:12 +02:00
* * charset : The charset used by the templates ( default to UTF - 8 ) .
2011-10-05 06:22:53 +02:00
*
* * base_template_class : The base template class to use for generated
* templates ( default to Twig_Template ) .
*
2018-05-10 12:24:53 +02:00
* * cache : An absolute path where to store the compiled templates ,
* a Twig_Cache_Interface implementation ,
* or false to disable compilation cache ( default ) .
2011-10-05 06:22:53 +02:00
*
2018-05-10 12:24:53 +02:00
* * auto_reload : Whether to reload the template if the original source changed .
2011-10-05 06:22:53 +02:00
* If you don ' t provide the auto_reload option , it will be
2018-05-10 12:24:53 +02:00
* determined automatically based on the debug value .
2011-10-05 06:22:53 +02:00
*
* * strict_variables : Whether to ignore invalid variables in templates
* ( default to false ) .
*
2013-08-01 21:20:12 +02:00
* * autoescape : Whether to enable auto - escaping ( default to html ) :
* * false : disable auto - escaping
* * true : equivalent to html
* * html , js : set the autoescaping to one of the supported strategies
2018-05-10 12:24:53 +02:00
* * name : set the autoescaping strategy based on the template name extension
* * PHP callback : a PHP callback that returns an escaping strategy based on the template " name "
2011-10-05 06:22:53 +02:00
*
* * optimizations : A flag that indicates which optimizations to apply
* ( default to - 1 which means that all optimizations are enabled ;
2013-08-01 21:20:12 +02:00
* set it to 0 to disable ) .
2011-10-05 06:22:53 +02:00
*
2018-05-10 12:24:53 +02:00
* @ param Twig_LoaderInterface $loader
2013-08-01 21:20:12 +02:00
* @ param array $options An array of options
2011-10-05 06:22:53 +02:00
*/
public function __construct ( Twig_LoaderInterface $loader = null , $options = array ())
{
if ( null !== $loader ) {
$this -> setLoader ( $loader );
2018-05-10 12:24:53 +02:00
} else {
@ trigger_error ( 'Not passing a Twig_LoaderInterface as the first constructor argument of Twig_Environment is deprecated since version 1.21.' , E_USER_DEPRECATED );
2011-10-05 06:22:53 +02:00
}
$options = array_merge ( array (
2018-05-10 12:24:53 +02:00
'debug' => false ,
'charset' => 'UTF-8' ,
2011-10-05 06:22:53 +02:00
'base_template_class' => 'Twig_Template' ,
2018-05-10 12:24:53 +02:00
'strict_variables' => false ,
'autoescape' => 'html' ,
'cache' => false ,
'auto_reload' => null ,
'optimizations' => - 1 ,
2011-10-05 06:22:53 +02:00
), $options );
2018-05-10 12:24:53 +02:00
$this -> debug = ( bool ) $options [ 'debug' ];
$this -> charset = strtoupper ( $options [ 'charset' ]);
$this -> baseTemplateClass = $options [ 'base_template_class' ];
$this -> autoReload = null === $options [ 'auto_reload' ] ? $this -> debug : ( bool ) $options [ 'auto_reload' ];
$this -> strictVariables = ( bool ) $options [ 'strict_variables' ];
2011-10-05 06:22:53 +02:00
$this -> setCache ( $options [ 'cache' ]);
2013-08-01 21:20:12 +02:00
$this -> addExtension ( new Twig_Extension_Core ());
$this -> addExtension ( new Twig_Extension_Escaper ( $options [ 'autoescape' ]));
$this -> addExtension ( new Twig_Extension_Optimizer ( $options [ 'optimizations' ]));
$this -> staging = new Twig_Extension_Staging ();
2018-05-10 12:24:53 +02:00
// For BC
if ( is_string ( $this -> originalCache )) {
$r = new ReflectionMethod ( $this , 'writeCacheFile' );
if ( __CLASS__ !== $r -> getDeclaringClass () -> getName ()) {
@ trigger_error ( 'The Twig_Environment::writeCacheFile method is deprecated since version 1.22 and will be removed in Twig 2.0.' , E_USER_DEPRECATED );
$this -> bcWriteCacheFile = true ;
}
$r = new ReflectionMethod ( $this , 'getCacheFilename' );
if ( __CLASS__ !== $r -> getDeclaringClass () -> getName ()) {
@ trigger_error ( 'The Twig_Environment::getCacheFilename method is deprecated since version 1.22 and will be removed in Twig 2.0.' , E_USER_DEPRECATED );
$this -> bcGetCacheFilename = true ;
}
}
2011-10-05 06:22:53 +02:00
}
/**
* Gets the base template class for compiled templates .
*
* @ return string The base template class name
*/
public function getBaseTemplateClass ()
{
return $this -> baseTemplateClass ;
}
/**
* Sets the base template class for compiled templates .
*
* @ param string $class The base template class name
*/
public function setBaseTemplateClass ( $class )
{
$this -> baseTemplateClass = $class ;
2018-05-10 12:24:53 +02:00
$this -> updateOptionsHash ();
2011-10-05 06:22:53 +02:00
}
/**
* Enables debugging mode .
*/
public function enableDebug ()
{
$this -> debug = true ;
2018-05-10 12:24:53 +02:00
$this -> updateOptionsHash ();
2011-10-05 06:22:53 +02:00
}
/**
* Disables debugging mode .
*/
public function disableDebug ()
{
$this -> debug = false ;
2018-05-10 12:24:53 +02:00
$this -> updateOptionsHash ();
2011-10-05 06:22:53 +02:00
}
/**
* Checks if debug mode is enabled .
*
2018-05-10 12:24:53 +02:00
* @ return bool true if debug mode is enabled , false otherwise
2011-10-05 06:22:53 +02:00
*/
public function isDebug ()
{
return $this -> debug ;
}
/**
* Enables the auto_reload option .
*/
public function enableAutoReload ()
{
$this -> autoReload = true ;
}
/**
* Disables the auto_reload option .
*/
public function disableAutoReload ()
{
$this -> autoReload = false ;
}
/**
* Checks if the auto_reload option is enabled .
*
2018-05-10 12:24:53 +02:00
* @ return bool true if auto_reload is enabled , false otherwise
2011-10-05 06:22:53 +02:00
*/
public function isAutoReload ()
{
return $this -> autoReload ;
}
/**
* Enables the strict_variables option .
*/
public function enableStrictVariables ()
{
$this -> strictVariables = true ;
2018-05-10 12:24:53 +02:00
$this -> updateOptionsHash ();
2011-10-05 06:22:53 +02:00
}
/**
* Disables the strict_variables option .
*/
public function disableStrictVariables ()
{
$this -> strictVariables = false ;
2018-05-10 12:24:53 +02:00
$this -> updateOptionsHash ();
2011-10-05 06:22:53 +02:00
}
/**
* Checks if the strict_variables option is enabled .
*
2018-05-10 12:24:53 +02:00
* @ return bool true if strict_variables is enabled , false otherwise
2011-10-05 06:22:53 +02:00
*/
public function isStrictVariables ()
{
return $this -> strictVariables ;
}
/**
2018-05-10 12:24:53 +02:00
* Gets the current cache implementation .
*
* @ param bool $original Whether to return the original cache option or the real cache instance
2011-10-05 06:22:53 +02:00
*
2018-05-10 12:24:53 +02:00
* @ return Twig_CacheInterface | string | false A Twig_CacheInterface implementation ,
* an absolute path to the compiled templates ,
* or false to disable cache
2011-10-05 06:22:53 +02:00
*/
2018-05-10 12:24:53 +02:00
public function getCache ( $original = true )
2011-10-05 06:22:53 +02:00
{
2018-05-10 12:24:53 +02:00
return $original ? $this -> originalCache : $this -> cache ;
2011-10-05 06:22:53 +02:00
}
2018-05-10 12:24:53 +02:00
/**
* Sets the current cache implementation .
*
* @ param Twig_CacheInterface | string | false $cache A Twig_CacheInterface implementation ,
* an absolute path to the compiled templates ,
* or false to disable cache
*/
2011-10-05 06:22:53 +02:00
public function setCache ( $cache )
{
2018-05-10 12:24:53 +02:00
if ( is_string ( $cache )) {
$this -> originalCache = $cache ;
$this -> cache = new Twig_Cache_Filesystem ( $cache );
} elseif ( false === $cache ) {
$this -> originalCache = $cache ;
$this -> cache = new Twig_Cache_Null ();
} elseif ( null === $cache ) {
@ trigger_error ( 'Using "null" as the cache strategy is deprecated since version 1.23 and will be removed in Twig 2.0.' , E_USER_DEPRECATED );
$this -> originalCache = false ;
$this -> cache = new Twig_Cache_Null ();
} elseif ( $cache instanceof Twig_CacheInterface ) {
$this -> originalCache = $this -> cache = $cache ;
} else {
throw new LogicException ( sprintf ( 'Cache can only be a string, false, or a Twig_CacheInterface implementation.' ));
}
2011-10-05 06:22:53 +02:00
}
/**
* Gets the cache filename for a given template .
*
* @ param string $name The template name
*
2018-05-10 12:24:53 +02:00
* @ return string | false The cache file name or false when caching is disabled
*
* @ deprecated since 1.22 ( to be removed in 2.0 )
2011-10-05 06:22:53 +02:00
*/
public function getCacheFilename ( $name )
{
2018-05-10 12:24:53 +02:00
@ trigger_error ( sprintf ( 'The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.' , __METHOD__ ), E_USER_DEPRECATED );
2011-10-05 06:22:53 +02:00
2018-05-10 12:24:53 +02:00
$key = $this -> cache -> generateKey ( $name , $this -> getTemplateClass ( $name ));
2011-10-05 06:22:53 +02:00
2018-05-10 12:24:53 +02:00
return ! $key ? false : $key ;
2011-10-05 06:22:53 +02:00
}
/**
* Gets the template class associated with the given string .
*
2018-05-10 12:24:53 +02:00
* The generated template class is based on the following parameters :
*
* * The cache key for the given template ;
* * The currently enabled extensions ;
* * Whether the Twig C extension is available or not ;
* * PHP version ;
* * Twig version ;
* * Options with what environment was created .
*
* @ param string $name The name for which to calculate the template class name
* @ param int | null $index The index if it is an embedded template
2011-10-05 06:22:53 +02:00
*
* @ return string The template class name
*/
2013-08-01 21:20:12 +02:00
public function getTemplateClass ( $name , $index = null )
2011-10-05 06:22:53 +02:00
{
2018-05-10 12:24:53 +02:00
$key = $this -> getLoader () -> getCacheKey ( $name ) . $this -> optionsHash ;
2013-09-19 08:08:25 +02:00
2018-05-10 12:24:53 +02:00
return $this -> templateClassPrefix . hash ( 'sha256' , $key ) . ( null === $index ? '' : '_' . $index );
2011-10-05 06:22:53 +02:00
}
/**
* Gets the template class prefix .
*
* @ return string The template class prefix
2018-05-10 12:24:53 +02:00
*
* @ deprecated since 1.22 ( to be removed in 2.0 )
2011-10-05 06:22:53 +02:00
*/
public function getTemplateClassPrefix ()
{
2018-05-10 12:24:53 +02:00
@ trigger_error ( sprintf ( 'The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.' , __METHOD__ ), E_USER_DEPRECATED );
2011-10-05 06:22:53 +02:00
return $this -> templateClassPrefix ;
}
/**
* Renders a template .
*
* @ param string $name The template name
* @ param array $context An array of parameters to pass to the template
*
* @ return string The rendered template
2018-05-10 12:24:53 +02:00
*
* @ throws Twig_Error_Loader When the template cannot be found
* @ throws Twig_Error_Syntax When an error occurred during compilation
* @ throws Twig_Error_Runtime When an error occurred during rendering
2011-10-05 06:22:53 +02:00
*/
public function render ( $name , array $context = array ())
{
return $this -> loadTemplate ( $name ) -> render ( $context );
}
2013-08-01 21:20:12 +02:00
/**
* Displays a template .
*
* @ param string $name The template name
* @ param array $context An array of parameters to pass to the template
2018-05-10 12:24:53 +02:00
*
* @ throws Twig_Error_Loader When the template cannot be found
* @ throws Twig_Error_Syntax When an error occurred during compilation
* @ throws Twig_Error_Runtime When an error occurred during rendering
2013-08-01 21:20:12 +02:00
*/
public function display ( $name , array $context = array ())
{
$this -> loadTemplate ( $name ) -> display ( $context );
}
2011-10-05 06:22:53 +02:00
/**
2018-05-10 12:24:53 +02:00
* Loads a template .
2011-10-05 06:22:53 +02:00
*
2018-05-10 12:24:53 +02:00
* @ param string | Twig_TemplateWrapper | Twig_Template $name The template name
*
* @ throws Twig_Error_Loader When the template cannot be found
* @ throws Twig_Error_Runtime When a previously generated cache is corrupted
* @ throws Twig_Error_Syntax When an error occurred during compilation
*
* @ return Twig_TemplateWrapper
*/
public function load ( $name )
{
if ( $name instanceof Twig_TemplateWrapper ) {
return $name ;
}
if ( $name instanceof Twig_Template ) {
return new Twig_TemplateWrapper ( $this , $name );
}
return new Twig_TemplateWrapper ( $this , $this -> loadTemplate ( $name ));
}
/**
* Loads a template internal representation .
*
* This method is for internal use only and should never be called
* directly .
*
* @ param string $name The template name
* @ param int $index The index if it is an embedded template
2011-10-05 06:22:53 +02:00
*
* @ return Twig_TemplateInterface A template instance representing the given template name
2018-05-10 12:24:53 +02:00
*
* @ throws Twig_Error_Loader When the template cannot be found
* @ throws Twig_Error_Runtime When a previously generated cache is corrupted
* @ throws Twig_Error_Syntax When an error occurred during compilation
*
* @ internal
2011-10-05 06:22:53 +02:00
*/
2013-08-01 21:20:12 +02:00
public function loadTemplate ( $name , $index = null )
2011-10-05 06:22:53 +02:00
{
2018-05-10 12:24:53 +02:00
$cls = $mainCls = $this -> getTemplateClass ( $name );
if ( null !== $index ) {
$cls .= '_' . $index ;
}
2011-10-05 06:22:53 +02:00
if ( isset ( $this -> loadedTemplates [ $cls ])) {
return $this -> loadedTemplates [ $cls ];
}
if ( ! class_exists ( $cls , false )) {
2018-05-10 12:24:53 +02:00
if ( $this -> bcGetCacheFilename ) {
$key = $this -> getCacheFilename ( $name );
2011-10-05 06:22:53 +02:00
} else {
2018-05-10 12:24:53 +02:00
$key = $this -> cache -> generateKey ( $name , $mainCls );
}
if ( ! $this -> isAutoReload () || $this -> isTemplateFresh ( $name , $this -> cache -> getTimestamp ( $key ))) {
$this -> cache -> load ( $key );
}
if ( ! class_exists ( $cls , false )) {
$loader = $this -> getLoader ();
if ( ! $loader instanceof Twig_SourceContextLoaderInterface ) {
$source = new Twig_Source ( $loader -> getSource ( $name ), $name );
} else {
$source = $loader -> getSourceContext ( $name );
}
$content = $this -> compileSource ( $source );
if ( $this -> bcWriteCacheFile ) {
$this -> writeCacheFile ( $key , $content );
} else {
$this -> cache -> write ( $key , $content );
$this -> cache -> load ( $key );
}
if ( ! class_exists ( $mainCls , false )) {
/* Last line of defense if either $this -> bcWriteCacheFile was used ,
* $this -> cache is implemented as a no - op or we have a race condition
* where the cache was cleared between the above calls to write to and load from
* the cache .
*/
eval ( '?>' . $content );
2011-10-05 06:22:53 +02:00
}
2018-05-10 12:24:53 +02:00
}
2011-10-05 06:22:53 +02:00
2018-05-10 12:24:53 +02:00
if ( ! class_exists ( $cls , false )) {
throw new Twig_Error_Runtime ( sprintf ( 'Failed to load Twig template "%s", index "%s": cache is corrupted.' , $name , $index ), - 1 , $source );
2011-10-05 06:22:53 +02:00
}
}
if ( ! $this -> runtimeInitialized ) {
$this -> initRuntime ();
}
2018-05-10 12:24:53 +02:00
if ( isset ( $this -> loading [ $cls ])) {
throw new Twig_Error_Runtime ( sprintf ( 'Circular reference detected for Twig template "%s", path: %s.' , $name , implode ( ' -> ' , array_merge ( $this -> loading , array ( $name )))));
}
$this -> loading [ $cls ] = $name ;
try {
$this -> loadedTemplates [ $cls ] = new $cls ( $this );
unset ( $this -> loading [ $cls ]);
} catch ( \Exception $e ) {
unset ( $this -> loading [ $cls ]);
throw $e ;
}
return $this -> loadedTemplates [ $cls ];
}
/**
* Creates a template from source .
*
* This method should not be used as a generic way to load templates .
*
* @ param string $template The template name
*
* @ return Twig_Template A template instance representing the given template name
*
* @ throws Twig_Error_Loader When the template cannot be found
* @ throws Twig_Error_Syntax When an error occurred during compilation
*/
public function createTemplate ( $template )
{
$name = sprintf ( '__string_template__%s' , hash ( 'sha256' , $template , false ));
$loader = new Twig_Loader_Chain ( array (
new Twig_Loader_Array ( array ( $name => $template )),
$current = $this -> getLoader (),
));
$this -> setLoader ( $loader );
try {
$template = $this -> loadTemplate ( $name );
} catch ( Exception $e ) {
$this -> setLoader ( $current );
throw $e ;
} catch ( Throwable $e ) {
$this -> setLoader ( $current );
throw $e ;
}
$this -> setLoader ( $current );
return $template ;
2011-10-05 06:22:53 +02:00
}
2013-08-01 21:20:12 +02:00
/**
* Returns true if the template is still fresh .
*
* Besides checking the loader for freshness information ,
* this method also checks if the enabled extensions have
* not changed .
*
2018-05-10 12:24:53 +02:00
* @ param string $name The template name
* @ param int $time The last modification time of the cached template
2013-08-01 21:20:12 +02:00
*
2018-05-10 12:24:53 +02:00
* @ return bool true if the template is fresh , false otherwise
2013-08-01 21:20:12 +02:00
*/
public function isTemplateFresh ( $name , $time )
{
2018-05-10 12:24:53 +02:00
if ( 0 === $this -> lastModifiedExtension ) {
foreach ( $this -> extensions as $extension ) {
$r = new ReflectionObject ( $extension );
if ( file_exists ( $r -> getFileName ()) && ( $extensionTime = filemtime ( $r -> getFileName ())) > $this -> lastModifiedExtension ) {
$this -> lastModifiedExtension = $extensionTime ;
}
2013-08-01 21:20:12 +02:00
}
}
2018-05-10 12:24:53 +02:00
return $this -> lastModifiedExtension <= $time && $this -> getLoader () -> isFresh ( $name , $time );
2013-08-01 21:20:12 +02:00
}
2018-05-10 12:24:53 +02:00
/**
* Tries to load a template consecutively from an array .
*
* Similar to loadTemplate () but it also accepts instances of Twig_Template and
* Twig_TemplateWrapper , and an array of templates where each is tried to be loaded .
*
* @ param string | Twig_Template | Twig_TemplateWrapper | array $names A template or an array of templates to try consecutively
*
* @ return Twig_Template | Twig_TemplateWrapper
*
* @ throws Twig_Error_Loader When none of the templates can be found
* @ throws Twig_Error_Syntax When an error occurred during compilation
*/
2011-10-05 06:22:53 +02:00
public function resolveTemplate ( $names )
{
if ( ! is_array ( $names )) {
$names = array ( $names );
}
foreach ( $names as $name ) {
if ( $name instanceof Twig_Template ) {
return $name ;
}
2018-05-10 12:24:53 +02:00
if ( $name instanceof Twig_TemplateWrapper ) {
return $name ;
}
2011-10-05 06:22:53 +02:00
try {
return $this -> loadTemplate ( $name );
} catch ( Twig_Error_Loader $e ) {
}
}
if ( 1 === count ( $names )) {
throw $e ;
}
throw new Twig_Error_Loader ( sprintf ( 'Unable to find one of the following templates: "%s".' , implode ( '", "' , $names )));
}
/**
* Clears the internal template cache .
2018-05-10 12:24:53 +02:00
*
* @ deprecated since 1.18 . 3 ( to be removed in 2.0 )
2011-10-05 06:22:53 +02:00
*/
public function clearTemplateCache ()
{
2018-05-10 12:24:53 +02:00
@ trigger_error ( sprintf ( 'The %s method is deprecated since version 1.18.3 and will be removed in Twig 2.0.' , __METHOD__ ), E_USER_DEPRECATED );
2011-10-05 06:22:53 +02:00
$this -> loadedTemplates = array ();
}
/**
* Clears the template cache files on the filesystem .
2018-05-10 12:24:53 +02:00
*
* @ deprecated since 1.22 ( to be removed in 2.0 )
2011-10-05 06:22:53 +02:00
*/
public function clearCacheFiles ()
{
2018-05-10 12:24:53 +02:00
@ trigger_error ( sprintf ( 'The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.' , __METHOD__ ), E_USER_DEPRECATED );
2011-10-05 06:22:53 +02:00
2018-05-10 12:24:53 +02:00
if ( is_string ( $this -> originalCache )) {
foreach ( new RecursiveIteratorIterator ( new RecursiveDirectoryIterator ( $this -> originalCache ), RecursiveIteratorIterator :: LEAVES_ONLY ) as $file ) {
if ( $file -> isFile ()) {
@ unlink ( $file -> getPathname ());
}
2011-10-05 06:22:53 +02:00
}
}
}
/**
* Gets the Lexer instance .
*
2018-05-10 12:24:53 +02:00
* @ return Twig_LexerInterface
*
* @ deprecated since 1.25 ( to be removed in 2.0 )
2011-10-05 06:22:53 +02:00
*/
public function getLexer ()
{
2018-05-10 12:24:53 +02:00
@ trigger_error ( sprintf ( 'The %s() method is deprecated since version 1.25 and will be removed in 2.0.' , __FUNCTION__ ), E_USER_DEPRECATED );
2011-10-05 06:22:53 +02:00
if ( null === $this -> lexer ) {
$this -> lexer = new Twig_Lexer ( $this );
}
return $this -> lexer ;
}
public function setLexer ( Twig_LexerInterface $lexer )
{
$this -> lexer = $lexer ;
}
/**
* Tokenizes a source code .
*
2018-05-10 12:24:53 +02:00
* @ param string | Twig_Source $source The template source code
* @ param string $name The template name ( deprecated )
*
* @ return Twig_TokenStream
2011-10-05 06:22:53 +02:00
*
2018-05-10 12:24:53 +02:00
* @ throws Twig_Error_Syntax When the code is syntactically wrong
2011-10-05 06:22:53 +02:00
*/
public function tokenize ( $source , $name = null )
{
2018-05-10 12:24:53 +02:00
if ( ! $source instanceof Twig_Source ) {
@ trigger_error ( sprintf ( 'Passing a string as the $source argument of %s() is deprecated since version 1.27. Pass a Twig_Source instance instead.' , __METHOD__ ), E_USER_DEPRECATED );
$source = new Twig_Source ( $source , $name );
}
if ( null === $this -> lexer ) {
$this -> lexer = new Twig_Lexer ( $this );
}
return $this -> lexer -> tokenize ( $source );
2011-10-05 06:22:53 +02:00
}
/**
* Gets the Parser instance .
*
2018-05-10 12:24:53 +02:00
* @ return Twig_ParserInterface
*
* @ deprecated since 1.25 ( to be removed in 2.0 )
2011-10-05 06:22:53 +02:00
*/
public function getParser ()
{
2018-05-10 12:24:53 +02:00
@ trigger_error ( sprintf ( 'The %s() method is deprecated since version 1.25 and will be removed in 2.0.' , __FUNCTION__ ), E_USER_DEPRECATED );
2011-10-05 06:22:53 +02:00
if ( null === $this -> parser ) {
$this -> parser = new Twig_Parser ( $this );
}
return $this -> parser ;
}
public function setParser ( Twig_ParserInterface $parser )
{
$this -> parser = $parser ;
}
/**
2018-05-10 12:24:53 +02:00
* Converts a token stream to a node tree .
2011-10-05 06:22:53 +02:00
*
2018-05-10 12:24:53 +02:00
* @ return Twig_Node_Module
2011-10-05 06:22:53 +02:00
*
2018-05-10 12:24:53 +02:00
* @ throws Twig_Error_Syntax When the token stream is syntactically or semantically wrong
2011-10-05 06:22:53 +02:00
*/
2018-05-10 12:24:53 +02:00
public function parse ( Twig_TokenStream $stream )
2011-10-05 06:22:53 +02:00
{
2018-05-10 12:24:53 +02:00
if ( null === $this -> parser ) {
$this -> parser = new Twig_Parser ( $this );
}
return $this -> parser -> parse ( $stream );
2011-10-05 06:22:53 +02:00
}
/**
* Gets the Compiler instance .
*
2018-05-10 12:24:53 +02:00
* @ return Twig_CompilerInterface
*
* @ deprecated since 1.25 ( to be removed in 2.0 )
2011-10-05 06:22:53 +02:00
*/
public function getCompiler ()
{
2018-05-10 12:24:53 +02:00
@ trigger_error ( sprintf ( 'The %s() method is deprecated since version 1.25 and will be removed in 2.0.' , __FUNCTION__ ), E_USER_DEPRECATED );
2011-10-05 06:22:53 +02:00
if ( null === $this -> compiler ) {
$this -> compiler = new Twig_Compiler ( $this );
}
return $this -> compiler ;
}
public function setCompiler ( Twig_CompilerInterface $compiler )
{
$this -> compiler = $compiler ;
}
/**
2018-05-10 12:24:53 +02:00
* Compiles a node and returns the PHP code .
2011-10-05 06:22:53 +02:00
*
* @ return string The compiled PHP source code
*/
public function compile ( Twig_NodeInterface $node )
{
2018-05-10 12:24:53 +02:00
if ( null === $this -> compiler ) {
$this -> compiler = new Twig_Compiler ( $this );
}
return $this -> compiler -> compile ( $node ) -> getSource ();
2011-10-05 06:22:53 +02:00
}
/**
* Compiles a template source code .
*
2018-05-10 12:24:53 +02:00
* @ param string | Twig_Source $source The template source code
* @ param string $name The template name ( deprecated )
2011-10-05 06:22:53 +02:00
*
* @ return string The compiled PHP source code
2018-05-10 12:24:53 +02:00
*
* @ throws Twig_Error_Syntax When there was an error during tokenizing , parsing or compiling
2011-10-05 06:22:53 +02:00
*/
public function compileSource ( $source , $name = null )
{
2018-05-10 12:24:53 +02:00
if ( ! $source instanceof Twig_Source ) {
@ trigger_error ( sprintf ( 'Passing a string as the $source argument of %s() is deprecated since version 1.27. Pass a Twig_Source instance instead.' , __METHOD__ ), E_USER_DEPRECATED );
$source = new Twig_Source ( $source , $name );
}
2011-10-05 06:22:53 +02:00
try {
2018-05-10 12:24:53 +02:00
return $this -> compile ( $this -> parse ( $this -> tokenize ( $source )));
2011-10-05 06:22:53 +02:00
} catch ( Twig_Error $e ) {
2018-05-10 12:24:53 +02:00
$e -> setSourceContext ( $source );
2011-10-05 06:22:53 +02:00
throw $e ;
} catch ( Exception $e ) {
2018-05-10 12:24:53 +02:00
throw new Twig_Error_Syntax ( sprintf ( 'An exception has been thrown during the compilation of a template ("%s").' , $e -> getMessage ()), - 1 , $source , $e );
2011-10-05 06:22:53 +02:00
}
}
public function setLoader ( Twig_LoaderInterface $loader )
{
2018-05-10 12:24:53 +02:00
if ( ! $loader instanceof Twig_SourceContextLoaderInterface && 0 !== strpos ( get_class ( $loader ), 'Mock_' )) {
@ trigger_error ( sprintf ( 'Twig loader "%s" should implement Twig_SourceContextLoaderInterface since version 1.27.' , get_class ( $loader )), E_USER_DEPRECATED );
}
2011-10-05 06:22:53 +02:00
$this -> loader = $loader ;
}
/**
* Gets the Loader instance .
*
2018-05-10 12:24:53 +02:00
* @ return Twig_LoaderInterface
2011-10-05 06:22:53 +02:00
*/
public function getLoader ()
{
2013-08-01 21:20:12 +02:00
if ( null === $this -> loader ) {
throw new LogicException ( 'You must set a loader first.' );
}
2011-10-05 06:22:53 +02:00
return $this -> loader ;
}
/**
* Sets the default template charset .
*
* @ param string $charset The default charset
*/
public function setCharset ( $charset )
{
2013-08-01 21:20:12 +02:00
$this -> charset = strtoupper ( $charset );
2011-10-05 06:22:53 +02:00
}
/**
* Gets the default template charset .
*
* @ return string The default charset
*/
public function getCharset ()
{
return $this -> charset ;
}
/**
* Initializes the runtime environment .
2018-05-10 12:24:53 +02:00
*
* @ deprecated since 1.23 ( to be removed in 2.0 )
2011-10-05 06:22:53 +02:00
*/
public function initRuntime ()
{
$this -> runtimeInitialized = true ;
2018-05-10 12:24:53 +02:00
foreach ( $this -> getExtensions () as $name => $extension ) {
if ( ! $extension instanceof Twig_Extension_InitRuntimeInterface ) {
$m = new ReflectionMethod ( $extension , 'initRuntime' );
if ( 'Twig_Extension' !== $m -> getDeclaringClass () -> getName ()) {
@ trigger_error ( sprintf ( 'Defining the initRuntime() method in the "%s" extension is deprecated since version 1.23. Use the `needs_environment` option to get the Twig_Environment instance in filters, functions, or tests; or explicitly implement Twig_Extension_InitRuntimeInterface if needed (not recommended).' , $name ), E_USER_DEPRECATED );
}
}
2011-10-05 06:22:53 +02:00
$extension -> initRuntime ( $this );
}
}
/**
* Returns true if the given extension is registered .
*
2018-05-10 12:24:53 +02:00
* @ param string $class The extension class name
2011-10-05 06:22:53 +02:00
*
2018-05-10 12:24:53 +02:00
* @ return bool Whether the extension is registered or not
*/
public function hasExtension ( $class )
{
$class = ltrim ( $class , '\\' );
if ( ! isset ( $this -> extensionsByClass [ $class ]) && class_exists ( $class , false )) {
// For BC/FC with namespaced aliases
$class = new ReflectionClass ( $class );
$class = $class -> name ;
}
if ( isset ( $this -> extensions [ $class ])) {
if ( $class !== get_class ( $this -> extensions [ $class ])) {
@ trigger_error ( sprintf ( 'Referencing the "%s" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead.' , $class ), E_USER_DEPRECATED );
}
return true ;
}
return isset ( $this -> extensionsByClass [ $class ]);
}
/**
* Adds a runtime loader .
2011-10-05 06:22:53 +02:00
*/
2018-05-10 12:24:53 +02:00
public function addRuntimeLoader ( Twig_RuntimeLoaderInterface $loader )
2011-10-05 06:22:53 +02:00
{
2018-05-10 12:24:53 +02:00
$this -> runtimeLoaders [] = $loader ;
2011-10-05 06:22:53 +02:00
}
/**
2018-05-10 12:24:53 +02:00
* Gets an extension by class name .
2011-10-05 06:22:53 +02:00
*
2018-05-10 12:24:53 +02:00
* @ param string $class The extension class name
2011-10-05 06:22:53 +02:00
*
2018-05-10 12:24:53 +02:00
* @ return Twig_ExtensionInterface
2011-10-05 06:22:53 +02:00
*/
2018-05-10 12:24:53 +02:00
public function getExtension ( $class )
2011-10-05 06:22:53 +02:00
{
2018-05-10 12:24:53 +02:00
$class = ltrim ( $class , '\\' );
if ( ! isset ( $this -> extensionsByClass [ $class ]) && class_exists ( $class , false )) {
// For BC/FC with namespaced aliases
$class = new ReflectionClass ( $class );
$class = $class -> name ;
}
if ( isset ( $this -> extensions [ $class ])) {
if ( $class !== get_class ( $this -> extensions [ $class ])) {
@ trigger_error ( sprintf ( 'Referencing the "%s" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead.' , $class ), E_USER_DEPRECATED );
}
return $this -> extensions [ $class ];
}
if ( ! isset ( $this -> extensionsByClass [ $class ])) {
throw new Twig_Error_Runtime ( sprintf ( 'The "%s" extension is not enabled.' , $class ));
2011-10-05 06:22:53 +02:00
}
2018-05-10 12:24:53 +02:00
return $this -> extensionsByClass [ $class ];
2011-10-05 06:22:53 +02:00
}
/**
2018-05-10 12:24:53 +02:00
* Returns the runtime implementation of a Twig element ( filter / function / test ) .
*
* @ param string $class A runtime class name
2011-10-05 06:22:53 +02:00
*
2018-05-10 12:24:53 +02:00
* @ return object The runtime implementation
*
* @ throws Twig_Error_Runtime When the template cannot be found
2011-10-05 06:22:53 +02:00
*/
2018-05-10 12:24:53 +02:00
public function getRuntime ( $class )
{
if ( isset ( $this -> runtimes [ $class ])) {
return $this -> runtimes [ $class ];
}
foreach ( $this -> runtimeLoaders as $loader ) {
if ( null !== $runtime = $loader -> load ( $class )) {
return $this -> runtimes [ $class ] = $runtime ;
}
}
throw new Twig_Error_Runtime ( sprintf ( 'Unable to load the "%s" runtime.' , $class ));
}
2011-10-05 06:22:53 +02:00
public function addExtension ( Twig_ExtensionInterface $extension )
{
2013-08-01 21:20:12 +02:00
if ( $this -> extensionInitialized ) {
throw new LogicException ( sprintf ( 'Unable to register extension "%s" as extensions have already been initialized.' , $extension -> getName ()));
}
2018-05-10 12:24:53 +02:00
$class = get_class ( $extension );
if ( $class !== $extension -> getName ()) {
if ( isset ( $this -> extensions [ $extension -> getName ()])) {
unset ( $this -> extensions [ $extension -> getName ()], $this -> extensionsByClass [ $class ]);
@ trigger_error ( sprintf ( 'The possibility to register the same extension twice ("%s") is deprecated since version 1.23 and will be removed in Twig 2.0. Use proper PHP inheritance instead.' , $extension -> getName ()), E_USER_DEPRECATED );
}
}
$this -> lastModifiedExtension = 0 ;
$this -> extensionsByClass [ $class ] = $extension ;
2011-10-05 06:22:53 +02:00
$this -> extensions [ $extension -> getName ()] = $extension ;
2018-05-10 12:24:53 +02:00
$this -> updateOptionsHash ();
2011-10-05 06:22:53 +02:00
}
/**
* Removes an extension by name .
*
2013-08-01 21:20:12 +02:00
* This method is deprecated and you should not use it .
*
2011-10-05 06:22:53 +02:00
* @ param string $name The extension name
2013-08-01 21:20:12 +02:00
*
* @ deprecated since 1.12 ( to be removed in 2.0 )
2011-10-05 06:22:53 +02:00
*/
public function removeExtension ( $name )
{
2018-05-10 12:24:53 +02:00
@ trigger_error ( sprintf ( 'The %s method is deprecated since version 1.12 and will be removed in Twig 2.0.' , __METHOD__ ), E_USER_DEPRECATED );
2013-08-01 21:20:12 +02:00
if ( $this -> extensionInitialized ) {
throw new LogicException ( sprintf ( 'Unable to remove extension "%s" as extensions have already been initialized.' , $name ));
}
2018-05-10 12:24:53 +02:00
$class = ltrim ( $name , '\\' );
if ( ! isset ( $this -> extensionsByClass [ $class ]) && class_exists ( $class , false )) {
// For BC/FC with namespaced aliases
$class = new ReflectionClass ( $class );
$class = $class -> name ;
}
if ( isset ( $this -> extensions [ $class ])) {
if ( $class !== get_class ( $this -> extensions [ $class ])) {
@ trigger_error ( sprintf ( 'Referencing the "%s" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead.' , $class ), E_USER_DEPRECATED );
}
unset ( $this -> extensions [ $class ]);
}
unset ( $this -> extensions [ $class ]);
$this -> updateOptionsHash ();
2011-10-05 06:22:53 +02:00
}
/**
* Registers an array of extensions .
*
* @ param array $extensions An array of extensions
*/
public function setExtensions ( array $extensions )
{
foreach ( $extensions as $extension ) {
$this -> addExtension ( $extension );
}
}
/**
* Returns all registered extensions .
*
2018-05-10 12:24:53 +02:00
* @ return Twig_ExtensionInterface [] An array of extensions ( keys are for internal usage only and should not be relied on )
2011-10-05 06:22:53 +02:00
*/
public function getExtensions ()
{
return $this -> extensions ;
}
public function addTokenParser ( Twig_TokenParserInterface $parser )
{
2013-08-01 21:20:12 +02:00
if ( $this -> extensionInitialized ) {
throw new LogicException ( 'Unable to add a token parser as extensions have already been initialized.' );
2011-10-05 06:22:53 +02:00
}
2013-08-01 21:20:12 +02:00
$this -> staging -> addTokenParser ( $parser );
2011-10-05 06:22:53 +02:00
}
/**
* Gets the registered Token Parsers .
*
2018-05-10 12:24:53 +02:00
* @ return Twig_TokenParserBrokerInterface
*
* @ internal
2011-10-05 06:22:53 +02:00
*/
public function getTokenParsers ()
{
2013-08-01 21:20:12 +02:00
if ( ! $this -> extensionInitialized ) {
$this -> initExtensions ();
2011-10-05 06:22:53 +02:00
}
return $this -> parsers ;
}
2013-08-01 21:20:12 +02:00
/**
* Gets registered tags .
*
* Be warned that this method cannot return tags defined by Twig_TokenParserBrokerInterface classes .
*
2018-05-10 12:24:53 +02:00
* @ return Twig_TokenParserInterface []
*
* @ internal
2013-08-01 21:20:12 +02:00
*/
public function getTags ()
{
$tags = array ();
foreach ( $this -> getTokenParsers () -> getParsers () as $parser ) {
if ( $parser instanceof Twig_TokenParserInterface ) {
$tags [ $parser -> getTag ()] = $parser ;
}
}
return $tags ;
}
2011-10-05 06:22:53 +02:00
public function addNodeVisitor ( Twig_NodeVisitorInterface $visitor )
{
2013-08-01 21:20:12 +02:00
if ( $this -> extensionInitialized ) {
2013-09-19 08:08:25 +02:00
throw new LogicException ( 'Unable to add a node visitor as extensions have already been initialized.' );
2011-10-05 06:22:53 +02:00
}
2013-08-01 21:20:12 +02:00
$this -> staging -> addNodeVisitor ( $visitor );
2011-10-05 06:22:53 +02:00
}
/**
* Gets the registered Node Visitors .
*
2018-05-10 12:24:53 +02:00
* @ return Twig_NodeVisitorInterface []
*
* @ internal
2011-10-05 06:22:53 +02:00
*/
public function getNodeVisitors ()
{
2013-08-01 21:20:12 +02:00
if ( ! $this -> extensionInitialized ) {
$this -> initExtensions ();
2011-10-05 06:22:53 +02:00
}
return $this -> visitors ;
}
/**
* Registers a Filter .
*
2013-08-01 21:20:12 +02:00
* @ param string | Twig_SimpleFilter $name The filter name or a Twig_SimpleFilter instance
2018-05-10 12:24:53 +02:00
* @ param Twig_FilterInterface | Twig_SimpleFilter $filter
2011-10-05 06:22:53 +02:00
*/
2013-08-01 21:20:12 +02:00
public function addFilter ( $name , $filter = null )
2011-10-05 06:22:53 +02:00
{
2013-08-01 21:20:12 +02:00
if ( ! $name instanceof Twig_SimpleFilter && ! ( $filter instanceof Twig_SimpleFilter || $filter instanceof Twig_FilterInterface )) {
2018-05-10 12:24:53 +02:00
throw new LogicException ( 'A filter must be an instance of Twig_FilterInterface or Twig_SimpleFilter.' );
2011-10-05 06:22:53 +02:00
}
2013-08-01 21:20:12 +02:00
if ( $name instanceof Twig_SimpleFilter ) {
$filter = $name ;
$name = $filter -> getName ();
2018-05-10 12:24:53 +02:00
} else {
@ trigger_error ( sprintf ( 'Passing a name as a first argument to the %s method is deprecated since version 1.21. Pass an instance of "Twig_SimpleFilter" instead when defining filter "%s".' , __METHOD__ , $name ), E_USER_DEPRECATED );
2013-08-01 21:20:12 +02:00
}
2018-05-10 12:24:53 +02:00
2013-08-01 21:20:12 +02:00
if ( $this -> extensionInitialized ) {
throw new LogicException ( sprintf ( 'Unable to add filter "%s" as extensions have already been initialized.' , $name ));
}
2018-05-10 12:24:53 +02:00
2013-08-01 21:20:12 +02:00
$this -> staging -> addFilter ( $name , $filter );
2011-10-05 06:22:53 +02:00
}
/**
* Get a filter by name .
*
* Subclasses may override this method and load filters differently ;
* so no list of filters is available .
*
* @ param string $name The filter name
*
2013-08-01 21:20:12 +02:00
* @ return Twig_Filter | false A Twig_Filter instance or false if the filter does not exist
2018-05-10 12:24:53 +02:00
*
* @ internal
2011-10-05 06:22:53 +02:00
*/
public function getFilter ( $name )
{
2013-08-01 21:20:12 +02:00
if ( ! $this -> extensionInitialized ) {
$this -> initExtensions ();
2011-10-05 06:22:53 +02:00
}
if ( isset ( $this -> filters [ $name ])) {
return $this -> filters [ $name ];
}
2013-08-01 21:20:12 +02:00
foreach ( $this -> filters as $pattern => $filter ) {
$pattern = str_replace ( '\\*' , '(.*?)' , preg_quote ( $pattern , '#' ), $count );
if ( $count ) {
if ( preg_match ( '#^' . $pattern . '$#' , $name , $matches )) {
array_shift ( $matches );
$filter -> setArguments ( $matches );
return $filter ;
}
}
}
2011-10-05 06:22:53 +02:00
foreach ( $this -> filterCallbacks as $callback ) {
if ( false !== $filter = call_user_func ( $callback , $name )) {
return $filter ;
}
}
return false ;
}
public function registerUndefinedFilterCallback ( $callable )
{
$this -> filterCallbacks [] = $callable ;
}
/**
* Gets the registered Filters .
*
2018-05-10 12:24:53 +02:00
* Be warned that this method cannot return filters defined with registerUndefinedFilterCallback .
2013-08-01 21:20:12 +02:00
*
2018-05-10 12:24:53 +02:00
* @ return Twig_FilterInterface []
2013-08-01 21:20:12 +02:00
*
* @ see registerUndefinedFilterCallback
2018-05-10 12:24:53 +02:00
*
* @ internal
2011-10-05 06:22:53 +02:00
*/
2013-08-01 21:20:12 +02:00
public function getFilters ()
2011-10-05 06:22:53 +02:00
{
2013-08-01 21:20:12 +02:00
if ( ! $this -> extensionInitialized ) {
$this -> initExtensions ();
2011-10-05 06:22:53 +02:00
}
2013-08-01 21:20:12 +02:00
return $this -> filters ;
2011-10-05 06:22:53 +02:00
}
/**
* Registers a Test .
*
2013-08-01 21:20:12 +02:00
* @ param string | Twig_SimpleTest $name The test name or a Twig_SimpleTest instance
* @ param Twig_TestInterface | Twig_SimpleTest $test A Twig_TestInterface instance or a Twig_SimpleTest instance
2011-10-05 06:22:53 +02:00
*/
2013-08-01 21:20:12 +02:00
public function addTest ( $name , $test = null )
2011-10-05 06:22:53 +02:00
{
2013-08-01 21:20:12 +02:00
if ( ! $name instanceof Twig_SimpleTest && ! ( $test instanceof Twig_SimpleTest || $test instanceof Twig_TestInterface )) {
2018-05-10 12:24:53 +02:00
throw new LogicException ( 'A test must be an instance of Twig_TestInterface or Twig_SimpleTest.' );
2011-10-05 06:22:53 +02:00
}
2013-08-01 21:20:12 +02:00
if ( $name instanceof Twig_SimpleTest ) {
$test = $name ;
$name = $test -> getName ();
2018-05-10 12:24:53 +02:00
} else {
@ trigger_error ( sprintf ( 'Passing a name as a first argument to the %s method is deprecated since version 1.21. Pass an instance of "Twig_SimpleTest" instead when defining test "%s".' , __METHOD__ , $name ), E_USER_DEPRECATED );
2013-08-01 21:20:12 +02:00
}
2018-05-10 12:24:53 +02:00
2013-08-01 21:20:12 +02:00
if ( $this -> extensionInitialized ) {
throw new LogicException ( sprintf ( 'Unable to add test "%s" as extensions have already been initialized.' , $name ));
}
$this -> staging -> addTest ( $name , $test );
2011-10-05 06:22:53 +02:00
}
/**
* Gets the registered Tests .
*
2018-05-10 12:24:53 +02:00
* @ return Twig_TestInterface []
*
* @ internal
2011-10-05 06:22:53 +02:00
*/
public function getTests ()
{
2013-08-01 21:20:12 +02:00
if ( ! $this -> extensionInitialized ) {
$this -> initExtensions ();
2011-10-05 06:22:53 +02:00
}
return $this -> tests ;
}
2013-08-01 21:20:12 +02:00
/**
* Gets a test by name .
*
* @ param string $name The test name
*
* @ return Twig_Test | false A Twig_Test instance or false if the test does not exist
2018-05-10 12:24:53 +02:00
*
* @ internal
2013-08-01 21:20:12 +02:00
*/
public function getTest ( $name )
{
if ( ! $this -> extensionInitialized ) {
$this -> initExtensions ();
}
if ( isset ( $this -> tests [ $name ])) {
return $this -> tests [ $name ];
}
return false ;
}
2011-10-05 06:22:53 +02:00
/**
* Registers a Function .
*
2013-08-01 21:20:12 +02:00
* @ param string | Twig_SimpleFunction $name The function name or a Twig_SimpleFunction instance
2018-05-10 12:24:53 +02:00
* @ param Twig_FunctionInterface | Twig_SimpleFunction $function
2011-10-05 06:22:53 +02:00
*/
2013-08-01 21:20:12 +02:00
public function addFunction ( $name , $function = null )
2011-10-05 06:22:53 +02:00
{
2013-08-01 21:20:12 +02:00
if ( ! $name instanceof Twig_SimpleFunction && ! ( $function instanceof Twig_SimpleFunction || $function instanceof Twig_FunctionInterface )) {
2018-05-10 12:24:53 +02:00
throw new LogicException ( 'A function must be an instance of Twig_FunctionInterface or Twig_SimpleFunction.' );
2011-10-05 06:22:53 +02:00
}
2013-08-01 21:20:12 +02:00
if ( $name instanceof Twig_SimpleFunction ) {
$function = $name ;
$name = $function -> getName ();
2018-05-10 12:24:53 +02:00
} else {
@ trigger_error ( sprintf ( 'Passing a name as a first argument to the %s method is deprecated since version 1.21. Pass an instance of "Twig_SimpleFunction" instead when defining function "%s".' , __METHOD__ , $name ), E_USER_DEPRECATED );
2013-08-01 21:20:12 +02:00
}
2018-05-10 12:24:53 +02:00
2013-08-01 21:20:12 +02:00
if ( $this -> extensionInitialized ) {
throw new LogicException ( sprintf ( 'Unable to add function "%s" as extensions have already been initialized.' , $name ));
}
2018-05-10 12:24:53 +02:00
2013-08-01 21:20:12 +02:00
$this -> staging -> addFunction ( $name , $function );
2011-10-05 06:22:53 +02:00
}
/**
* Get a function by name .
*
* Subclasses may override this method and load functions differently ;
* so no list of functions is available .
*
* @ param string $name function name
*
2013-08-01 21:20:12 +02:00
* @ return Twig_Function | false A Twig_Function instance or false if the function does not exist
2018-05-10 12:24:53 +02:00
*
* @ internal
2011-10-05 06:22:53 +02:00
*/
public function getFunction ( $name )
{
2013-08-01 21:20:12 +02:00
if ( ! $this -> extensionInitialized ) {
$this -> initExtensions ();
2011-10-05 06:22:53 +02:00
}
if ( isset ( $this -> functions [ $name ])) {
return $this -> functions [ $name ];
}
2013-08-01 21:20:12 +02:00
foreach ( $this -> functions as $pattern => $function ) {
$pattern = str_replace ( '\\*' , '(.*?)' , preg_quote ( $pattern , '#' ), $count );
if ( $count ) {
if ( preg_match ( '#^' . $pattern . '$#' , $name , $matches )) {
array_shift ( $matches );
$function -> setArguments ( $matches );
return $function ;
}
}
}
2011-10-05 06:22:53 +02:00
foreach ( $this -> functionCallbacks as $callback ) {
if ( false !== $function = call_user_func ( $callback , $name )) {
return $function ;
}
}
return false ;
}
public function registerUndefinedFunctionCallback ( $callable )
{
$this -> functionCallbacks [] = $callable ;
}
2013-08-01 21:20:12 +02:00
/**
* Gets registered functions .
*
* Be warned that this method cannot return functions defined with registerUndefinedFunctionCallback .
*
2018-05-10 12:24:53 +02:00
* @ return Twig_FunctionInterface []
2013-08-01 21:20:12 +02:00
*
* @ see registerUndefinedFunctionCallback
2018-05-10 12:24:53 +02:00
*
* @ internal
2013-08-01 21:20:12 +02:00
*/
public function getFunctions ()
2011-10-05 06:22:53 +02:00
{
2013-08-01 21:20:12 +02:00
if ( ! $this -> extensionInitialized ) {
$this -> initExtensions ();
2011-10-05 06:22:53 +02:00
}
2013-08-01 21:20:12 +02:00
return $this -> functions ;
2011-10-05 06:22:53 +02:00
}
/**
* Registers a Global .
*
2013-08-01 21:20:12 +02:00
* New globals can be added before compiling or rendering a template ;
* but after , you can only update existing globals .
*
2011-10-05 06:22:53 +02:00
* @ param string $name The global name
* @ param mixed $value The global value
*/
public function addGlobal ( $name , $value )
{
2013-08-01 21:20:12 +02:00
if ( $this -> extensionInitialized || $this -> runtimeInitialized ) {
if ( null === $this -> globals ) {
$this -> globals = $this -> initGlobals ();
}
if ( ! array_key_exists ( $name , $this -> globals )) {
2018-05-10 12:24:53 +02:00
// The deprecation notice must be turned into the following exception in Twig 2.0
@ trigger_error ( sprintf ( 'Registering global variable "%s" at runtime or when the extensions have already been initialized is deprecated since version 1.21.' , $name ), E_USER_DEPRECATED );
//throw new LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name));
2013-08-01 21:20:12 +02:00
}
2011-10-05 06:22:53 +02:00
}
2013-08-01 21:20:12 +02:00
if ( $this -> extensionInitialized || $this -> runtimeInitialized ) {
// update the value
$this -> globals [ $name ] = $value ;
} else {
$this -> staging -> addGlobal ( $name , $value );
}
2011-10-05 06:22:53 +02:00
}
/**
* Gets the registered Globals .
*
* @ return array An array of globals
2018-05-10 12:24:53 +02:00
*
* @ internal
2011-10-05 06:22:53 +02:00
*/
public function getGlobals ()
{
2013-08-01 21:20:12 +02:00
if ( ! $this -> runtimeInitialized && ! $this -> extensionInitialized ) {
return $this -> initGlobals ();
}
2011-10-05 06:22:53 +02:00
if ( null === $this -> globals ) {
2013-08-01 21:20:12 +02:00
$this -> globals = $this -> initGlobals ();
2011-10-05 06:22:53 +02:00
}
return $this -> globals ;
}
2013-08-01 21:20:12 +02:00
/**
* Merges a context with the defined globals .
*
* @ param array $context An array representing the context
*
* @ return array The context merged with the globals
*/
public function mergeGlobals ( array $context )
{
// we don't use array_merge as the context being generally
// bigger than globals, this code is faster.
foreach ( $this -> getGlobals () as $key => $value ) {
if ( ! array_key_exists ( $key , $context )) {
$context [ $key ] = $value ;
}
}
return $context ;
}
2011-10-05 06:22:53 +02:00
/**
* Gets the registered unary Operators .
*
* @ return array An array of unary operators
2018-05-10 12:24:53 +02:00
*
* @ internal
2011-10-05 06:22:53 +02:00
*/
public function getUnaryOperators ()
{
2013-08-01 21:20:12 +02:00
if ( ! $this -> extensionInitialized ) {
$this -> initExtensions ();
2011-10-05 06:22:53 +02:00
}
return $this -> unaryOperators ;
}
/**
* Gets the registered binary Operators .
*
* @ return array An array of binary operators
2018-05-10 12:24:53 +02:00
*
* @ internal
2011-10-05 06:22:53 +02:00
*/
public function getBinaryOperators ()
{
2013-08-01 21:20:12 +02:00
if ( ! $this -> extensionInitialized ) {
$this -> initExtensions ();
2011-10-05 06:22:53 +02:00
}
return $this -> binaryOperators ;
}
2018-05-10 12:24:53 +02:00
/**
* @ deprecated since 1.23 ( to be removed in 2.0 )
*/
2013-08-01 21:20:12 +02:00
public function computeAlternatives ( $name , $items )
{
2018-05-10 12:24:53 +02:00
@ trigger_error ( sprintf ( 'The %s method is deprecated since version 1.23 and will be removed in Twig 2.0.' , __METHOD__ ), E_USER_DEPRECATED );
2013-08-01 21:20:12 +02:00
2018-05-10 12:24:53 +02:00
return Twig_Error_Syntax :: computeAlternatives ( $name , $items );
2013-08-01 21:20:12 +02:00
}
2018-05-10 12:24:53 +02:00
/**
* @ internal
*/
2013-08-01 21:20:12 +02:00
protected function initGlobals ()
{
$globals = array ();
2018-05-10 12:24:53 +02:00
foreach ( $this -> extensions as $name => $extension ) {
if ( ! $extension instanceof Twig_Extension_GlobalsInterface ) {
$m = new ReflectionMethod ( $extension , 'getGlobals' );
if ( 'Twig_Extension' !== $m -> getDeclaringClass () -> getName ()) {
@ trigger_error ( sprintf ( 'Defining the getGlobals() method in the "%s" extension without explicitly implementing Twig_Extension_GlobalsInterface is deprecated since version 1.23.' , $name ), E_USER_DEPRECATED );
}
}
2013-08-01 21:20:12 +02:00
$extGlob = $extension -> getGlobals ();
if ( ! is_array ( $extGlob )) {
throw new UnexpectedValueException ( sprintf ( '"%s::getGlobals()" must return an array of globals.' , get_class ( $extension )));
}
$globals [] = $extGlob ;
}
$globals [] = $this -> staging -> getGlobals ();
return call_user_func_array ( 'array_merge' , $globals );
}
2018-05-10 12:24:53 +02:00
/**
* @ internal
*/
2013-08-01 21:20:12 +02:00
protected function initExtensions ()
2011-10-05 06:22:53 +02:00
{
2013-08-01 21:20:12 +02:00
if ( $this -> extensionInitialized ) {
return ;
}
2018-05-10 12:24:53 +02:00
$this -> parsers = new Twig_TokenParserBroker ( array (), array (), false );
2013-08-01 21:20:12 +02:00
$this -> filters = array ();
$this -> functions = array ();
$this -> tests = array ();
$this -> visitors = array ();
2011-10-05 06:22:53 +02:00
$this -> unaryOperators = array ();
$this -> binaryOperators = array ();
2013-08-01 21:20:12 +02:00
foreach ( $this -> extensions as $extension ) {
$this -> initExtension ( $extension );
}
$this -> initExtension ( $this -> staging );
2018-05-10 12:24:53 +02:00
// Done at the end only, so that an exception during initialization does not mark the environment as initialized when catching the exception
$this -> extensionInitialized = true ;
2013-08-01 21:20:12 +02:00
}
2018-05-10 12:24:53 +02:00
/**
* @ internal
*/
2013-08-01 21:20:12 +02:00
protected function initExtension ( Twig_ExtensionInterface $extension )
{
// filters
foreach ( $extension -> getFilters () as $name => $filter ) {
2018-05-10 12:24:53 +02:00
if ( $filter instanceof Twig_SimpleFilter ) {
2013-08-01 21:20:12 +02:00
$name = $filter -> getName ();
2018-05-10 12:24:53 +02:00
} else {
@ trigger_error ( sprintf ( 'Using an instance of "%s" for filter "%s" is deprecated since version 1.21. Use Twig_SimpleFilter instead.' , get_class ( $filter ), $name ), E_USER_DEPRECATED );
2013-08-01 21:20:12 +02:00
}
$this -> filters [ $name ] = $filter ;
}
// functions
foreach ( $extension -> getFunctions () as $name => $function ) {
2018-05-10 12:24:53 +02:00
if ( $function instanceof Twig_SimpleFunction ) {
2013-08-01 21:20:12 +02:00
$name = $function -> getName ();
2018-05-10 12:24:53 +02:00
} else {
@ trigger_error ( sprintf ( 'Using an instance of "%s" for function "%s" is deprecated since version 1.21. Use Twig_SimpleFunction instead.' , get_class ( $function ), $name ), E_USER_DEPRECATED );
2013-08-01 21:20:12 +02:00
}
$this -> functions [ $name ] = $function ;
}
// tests
foreach ( $extension -> getTests () as $name => $test ) {
2018-05-10 12:24:53 +02:00
if ( $test instanceof Twig_SimpleTest ) {
2013-08-01 21:20:12 +02:00
$name = $test -> getName ();
2018-05-10 12:24:53 +02:00
} else {
@ trigger_error ( sprintf ( 'Using an instance of "%s" for test "%s" is deprecated since version 1.21. Use Twig_SimpleTest instead.' , get_class ( $test ), $name ), E_USER_DEPRECATED );
2011-10-05 06:22:53 +02:00
}
2013-08-01 21:20:12 +02:00
$this -> tests [ $name ] = $test ;
}
// token parsers
foreach ( $extension -> getTokenParsers () as $parser ) {
if ( $parser instanceof Twig_TokenParserInterface ) {
$this -> parsers -> addTokenParser ( $parser );
} elseif ( $parser instanceof Twig_TokenParserBrokerInterface ) {
2018-05-10 12:24:53 +02:00
@ trigger_error ( 'Registering a Twig_TokenParserBrokerInterface instance is deprecated since version 1.21.' , E_USER_DEPRECATED );
2013-08-01 21:20:12 +02:00
$this -> parsers -> addTokenParserBroker ( $parser );
} else {
2018-05-10 12:24:53 +02:00
throw new LogicException ( 'getTokenParsers() must return an array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances.' );
2013-08-01 21:20:12 +02:00
}
}
// node visitors
foreach ( $extension -> getNodeVisitors () as $visitor ) {
$this -> visitors [] = $visitor ;
}
// operators
if ( $operators = $extension -> getOperators ()) {
2018-05-10 12:24:53 +02:00
if ( ! is_array ( $operators )) {
throw new InvalidArgumentException ( sprintf ( '"%s::getOperators()" must return an array with operators, got "%s".' , get_class ( $extension ), is_object ( $operators ) ? get_class ( $operators ) : gettype ( $operators ) . ( is_resource ( $operators ) ? '' : '#' . $operators )));
}
2011-10-05 06:22:53 +02:00
if ( 2 !== count ( $operators )) {
2018-05-10 12:24:53 +02:00
throw new InvalidArgumentException ( sprintf ( '"%s::getOperators()" must return an array of 2 elements, got %d.' , get_class ( $extension ), count ( $operators )));
2011-10-05 06:22:53 +02:00
}
$this -> unaryOperators = array_merge ( $this -> unaryOperators , $operators [ 0 ]);
$this -> binaryOperators = array_merge ( $this -> binaryOperators , $operators [ 1 ]);
}
}
2018-05-10 12:24:53 +02:00
/**
* @ deprecated since 1.22 ( to be removed in 2.0 )
*/
2011-10-05 06:22:53 +02:00
protected function writeCacheFile ( $file , $content )
{
2018-05-10 12:24:53 +02:00
$this -> cache -> write ( $file , $content );
}
2011-10-05 06:22:53 +02:00
2018-05-10 12:24:53 +02:00
private function updateOptionsHash ()
{
$hashParts = array_merge (
array_keys ( $this -> extensions ),
array (
( int ) function_exists ( 'twig_template_get_attributes' ),
PHP_MAJOR_VERSION ,
PHP_MINOR_VERSION ,
self :: VERSION ,
( int ) $this -> debug ,
$this -> baseTemplateClass ,
( int ) $this -> strictVariables ,
)
);
$this -> optionsHash = implode ( ':' , $hashParts );
2011-10-05 06:22:53 +02:00
}
}
2018-05-10 12:24:53 +02:00
class_alias ( 'Twig_Environment' , 'Twig\Environment' , false );