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
* ( c ) Armin Ronacher
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 .
*/
/**
* Represents a module node .
*
2018-05-10 12:24:53 +02:00
* Consider this class as being final . If you need to customize the behavior of
* the generated class , consider adding nodes to the following nodes : display_start ,
* display_end , constructor_start , constructor_end , and class_end .
*
2013-08-01 21:20:12 +02:00
* @ author Fabien Potencier < fabien @ symfony . com >
2011-10-05 06:22:53 +02:00
*/
class Twig_Node_Module extends Twig_Node
{
2018-05-10 12:24:53 +02:00
private $source ;
public function __construct ( Twig_NodeInterface $body , Twig_Node_Expression $parent = null , Twig_NodeInterface $blocks , Twig_NodeInterface $macros , Twig_NodeInterface $traits , $embeddedTemplates , $name , $source = '' )
2011-10-05 06:22:53 +02:00
{
2018-05-10 12:24:53 +02:00
if ( ! $name instanceof Twig_Source ) {
@ trigger_error ( sprintf ( 'Passing a string as the $name argument of %s() is deprecated since version 1.27. Pass a Twig_Source instance instead.' , __METHOD__ ), E_USER_DEPRECATED );
$this -> source = new Twig_Source ( $source , $name );
} else {
$this -> source = $name ;
}
$nodes = array (
'body' => $body ,
'blocks' => $blocks ,
'macros' => $macros ,
'traits' => $traits ,
'display_start' => new Twig_Node (),
'display_end' => new Twig_Node (),
'constructor_start' => new Twig_Node (),
'constructor_end' => new Twig_Node (),
'class_end' => new Twig_Node (),
);
if ( null !== $parent ) {
$nodes [ 'parent' ] = $parent ;
}
2013-08-01 21:20:12 +02:00
// embedded templates are set as attributes so that they are only visited once by the visitors
2018-05-10 12:24:53 +02:00
parent :: __construct ( $nodes , array (
// source to be remove in 2.0
'source' => $this -> source -> getCode (),
// filename to be remove in 2.0 (use getTemplateName() instead)
'filename' => $this -> source -> getName (),
'index' => null ,
'embedded_templates' => $embeddedTemplates ,
), 1 );
// populate the template name of all node children
$this -> setTemplateName ( $this -> source -> getName ());
2013-08-01 21:20:12 +02:00
}
public function setIndex ( $index )
{
$this -> setAttribute ( 'index' , $index );
2011-10-05 06:22:53 +02:00
}
public function compile ( Twig_Compiler $compiler )
{
$this -> compileTemplate ( $compiler );
2013-08-01 21:20:12 +02:00
foreach ( $this -> getAttribute ( 'embedded_templates' ) as $template ) {
$compiler -> subcompile ( $template );
}
2011-10-05 06:22:53 +02:00
}
protected function compileTemplate ( Twig_Compiler $compiler )
{
2013-08-01 21:20:12 +02:00
if ( ! $this -> getAttribute ( 'index' )) {
$compiler -> write ( '<?php' );
}
2011-10-05 06:22:53 +02:00
$this -> compileClassHeader ( $compiler );
2018-05-10 12:24:53 +02:00
if (
count ( $this -> getNode ( 'blocks' ))
|| count ( $this -> getNode ( 'traits' ))
|| ! $this -> hasNode ( 'parent' )
|| $this -> getNode ( 'parent' ) instanceof Twig_Node_Expression_Constant
|| count ( $this -> getNode ( 'constructor_start' ))
|| count ( $this -> getNode ( 'constructor_end' ))
) {
2011-10-05 06:22:53 +02:00
$this -> compileConstructor ( $compiler );
}
$this -> compileGetParent ( $compiler );
2018-05-10 12:24:53 +02:00
$this -> compileDisplay ( $compiler );
2011-10-05 06:22:53 +02:00
$compiler -> subcompile ( $this -> getNode ( 'blocks' ));
$this -> compileMacros ( $compiler );
$this -> compileGetTemplateName ( $compiler );
$this -> compileIsTraitable ( $compiler );
2013-08-01 21:20:12 +02:00
$this -> compileDebugInfo ( $compiler );
2018-05-10 12:24:53 +02:00
$this -> compileGetSource ( $compiler );
$this -> compileGetSourceContext ( $compiler );
2011-10-05 06:22:53 +02:00
$this -> compileClassFooter ( $compiler );
}
protected function compileGetParent ( Twig_Compiler $compiler )
{
2018-05-10 12:24:53 +02:00
if ( ! $this -> hasNode ( 'parent' )) {
2013-08-01 21:20:12 +02:00
return ;
}
2018-05-10 12:24:53 +02:00
$parent = $this -> getNode ( 'parent' );
2013-08-01 21:20:12 +02:00
2011-10-05 06:22:53 +02:00
$compiler
-> write ( " protected function doGetParent(array \$ context) \n " , " { \n " )
-> indent ()
2018-05-10 12:24:53 +02:00
-> addDebugInfo ( $parent )
-> write ( 'return ' )
2011-10-05 06:22:53 +02:00
;
2018-05-10 12:24:53 +02:00
if ( $parent instanceof Twig_Node_Expression_Constant ) {
$compiler -> subcompile ( $parent );
2011-10-05 06:22:53 +02:00
} else {
2013-08-01 21:20:12 +02:00
$compiler
2018-05-10 12:24:53 +02:00
-> raw ( '$this->loadTemplate(' )
-> subcompile ( $parent )
-> raw ( ', ' )
-> repr ( $this -> source -> getName ())
-> raw ( ', ' )
-> repr ( $parent -> getTemplateLine ())
-> raw ( ')' )
2013-08-01 21:20:12 +02:00
;
2011-10-05 06:22:53 +02:00
}
$compiler
-> raw ( " ; \n " )
-> outdent ()
-> write ( " } \n \n " )
;
}
protected function compileClassHeader ( Twig_Compiler $compiler )
{
$compiler
2013-08-01 21:20:12 +02:00
-> write ( " \n \n " )
2018-05-10 12:24:53 +02:00
// if the template name contains */, add a blank to avoid a PHP parse error
-> write ( '/* ' . str_replace ( '*/' , '* /' , $this -> source -> getName ()) . " */ \n " )
-> write ( 'class ' . $compiler -> getEnvironment () -> getTemplateClass ( $this -> source -> getName (), $this -> getAttribute ( 'index' )))
2011-10-05 06:22:53 +02:00
-> raw ( sprintf ( " extends %s \n " , $compiler -> getEnvironment () -> getBaseTemplateClass ()))
-> write ( " { \n " )
-> indent ()
;
}
protected function compileConstructor ( Twig_Compiler $compiler )
{
$compiler
-> write ( " public function __construct(Twig_Environment \$ env) \n " , " { \n " )
-> indent ()
2018-05-10 12:24:53 +02:00
-> subcompile ( $this -> getNode ( 'constructor_start' ))
2011-10-05 06:22:53 +02:00
-> write ( " parent::__construct( \$ env); \n \n " )
;
2013-08-01 21:20:12 +02:00
// parent
2018-05-10 12:24:53 +02:00
if ( ! $this -> hasNode ( 'parent' )) {
2013-08-01 21:20:12 +02:00
$compiler -> write ( " \$ this->parent = false; \n \n " );
2018-05-10 12:24:53 +02:00
} elseif (( $parent = $this -> getNode ( 'parent' )) && $parent instanceof Twig_Node_Expression_Constant ) {
2013-08-01 21:20:12 +02:00
$compiler
2018-05-10 12:24:53 +02:00
-> addDebugInfo ( $parent )
-> write ( '$this->parent = $this->loadTemplate(' )
-> subcompile ( $parent )
-> raw ( ', ' )
-> repr ( $this -> source -> getName ())
-> raw ( ', ' )
-> repr ( $parent -> getTemplateLine ())
-> raw ( " ); \n " )
2013-08-01 21:20:12 +02:00
;
}
2011-10-05 06:22:53 +02:00
$countTraits = count ( $this -> getNode ( 'traits' ));
if ( $countTraits ) {
// traits
foreach ( $this -> getNode ( 'traits' ) as $i => $trait ) {
$this -> compileLoadTemplate ( $compiler , $trait -> getNode ( 'template' ), sprintf ( '$_trait_%s' , $i ));
$compiler
-> addDebugInfo ( $trait -> getNode ( 'template' ))
-> write ( sprintf ( " if (! \$ _trait_%s->isTraitable()) { \n " , $i ))
-> indent ()
-> write ( " throw new Twig_Error_Runtime('Template \" '. " )
-> subcompile ( $trait -> getNode ( 'template' ))
-> raw ( " .' \" cannot be used as a trait.'); \n " )
-> outdent ()
-> write ( " } \n " )
-> write ( sprintf ( " \$ _trait_%s_blocks = \$ _trait_%s->getBlocks(); \n \n " , $i , $i ))
;
foreach ( $trait -> getNode ( 'targets' ) as $key => $value ) {
$compiler
2018-05-10 12:24:53 +02:00
-> write ( sprintf ( 'if (!isset($_trait_%s_blocks[' , $i ))
-> string ( $key )
-> raw ( " ])) { \n " )
-> indent ()
-> write ( " throw new Twig_Error_Runtime(sprintf('Block " )
-> string ( $key )
-> raw ( ' is not defined in trait ' )
-> subcompile ( $trait -> getNode ( 'template' ))
-> raw ( " .')); \n " )
-> outdent ()
-> write ( " } \n \n " )
-> write ( sprintf ( '$_trait_%s_blocks[' , $i ))
2011-10-05 06:22:53 +02:00
-> subcompile ( $value )
2018-05-10 12:24:53 +02:00
-> raw ( sprintf ( '] = $_trait_%s_blocks[' , $i ))
2011-10-05 06:22:53 +02:00
-> string ( $key )
2018-05-10 12:24:53 +02:00
-> raw ( sprintf ( ']; unset($_trait_%s_blocks[' , $i ))
2011-10-05 06:22:53 +02:00
-> string ( $key )
-> raw ( " ]); \n \n " )
;
}
}
2013-08-01 21:20:12 +02:00
if ( $countTraits > 1 ) {
$compiler
-> write ( " \$ this->traits = array_merge( \n " )
-> indent ()
;
2018-05-10 12:24:53 +02:00
for ( $i = 0 ; $i < $countTraits ; ++ $i ) {
2013-08-01 21:20:12 +02:00
$compiler
2018-05-10 12:24:53 +02:00
-> write ( sprintf ( '$_trait_%s_blocks' . ( $i == $countTraits - 1 ? '' : ',' ) . " \n " , $i ))
2013-08-01 21:20:12 +02:00
;
}
2011-10-05 06:22:53 +02:00
$compiler
2013-08-01 21:20:12 +02:00
-> outdent ()
-> write ( " ); \n \n " )
;
} else {
$compiler
-> write ( " \$ this->traits = \$ _trait_0_blocks; \n \n " )
2011-10-05 06:22:53 +02:00
;
}
$compiler
2013-08-01 21:20:12 +02:00
-> write ( " \$ this->blocks = array_merge( \n " )
-> indent ()
-> write ( " \$ this->traits, \n " )
2011-10-05 06:22:53 +02:00
-> write ( " array( \n " )
;
} else {
$compiler
-> write ( " \$ this->blocks = array( \n " )
;
}
// blocks
$compiler
-> indent ()
;
foreach ( $this -> getNode ( 'blocks' ) as $name => $node ) {
$compiler
-> write ( sprintf ( " '%s' => array( \$ this, 'block_%s'), \n " , $name , $name ))
;
}
if ( $countTraits ) {
$compiler
-> outdent ()
-> write ( " ) \n " )
;
}
$compiler
-> outdent ()
-> write ( " ); \n " )
-> outdent ()
2018-05-10 12:24:53 +02:00
-> subcompile ( $this -> getNode ( 'constructor_end' ))
2013-09-19 08:08:25 +02:00
-> write ( " } \n \n " )
2011-10-05 06:22:53 +02:00
;
}
2018-05-10 12:24:53 +02:00
protected function compileDisplay ( Twig_Compiler $compiler )
2011-10-05 06:22:53 +02:00
{
$compiler
-> write ( " protected function doDisplay(array \$ context, array \$ blocks = array()) \n " , " { \n " )
-> indent ()
2018-05-10 12:24:53 +02:00
-> subcompile ( $this -> getNode ( 'display_start' ))
-> subcompile ( $this -> getNode ( 'body' ))
2011-10-05 06:22:53 +02:00
;
2018-05-10 12:24:53 +02:00
if ( $this -> hasNode ( 'parent' )) {
$parent = $this -> getNode ( 'parent' );
$compiler -> addDebugInfo ( $parent );
if ( $parent instanceof Twig_Node_Expression_Constant ) {
$compiler -> write ( '$this->parent' );
} else {
$compiler -> write ( '$this->getParent($context)' );
}
$compiler -> raw ( " ->display( \$ context, array_merge( \$ this->blocks, \$ blocks)); \n " );
}
2011-10-05 06:22:53 +02:00
$compiler
2018-05-10 12:24:53 +02:00
-> subcompile ( $this -> getNode ( 'display_end' ))
2011-10-05 06:22:53 +02:00
-> outdent ()
-> write ( " } \n \n " )
;
}
protected function compileClassFooter ( Twig_Compiler $compiler )
{
$compiler
2018-05-10 12:24:53 +02:00
-> subcompile ( $this -> getNode ( 'class_end' ))
2011-10-05 06:22:53 +02:00
-> outdent ()
-> write ( " } \n " )
;
}
protected function compileMacros ( Twig_Compiler $compiler )
{
$compiler -> subcompile ( $this -> getNode ( 'macros' ));
}
protected function compileGetTemplateName ( Twig_Compiler $compiler )
{
$compiler
-> write ( " public function getTemplateName() \n " , " { \n " )
-> indent ()
-> write ( 'return ' )
2018-05-10 12:24:53 +02:00
-> repr ( $this -> source -> getName ())
2011-10-05 06:22:53 +02:00
-> raw ( " ; \n " )
-> outdent ()
-> write ( " } \n \n " )
;
}
protected function compileIsTraitable ( Twig_Compiler $compiler )
{
// A template can be used as a trait if:
// * it has no parent
// * it has no macros
// * it has no body
//
// Put another way, a template can be used as a trait if it
// only contains blocks and use statements.
2018-05-10 12:24:53 +02:00
$traitable = ! $this -> hasNode ( 'parent' ) && 0 === count ( $this -> getNode ( 'macros' ));
2011-10-05 06:22:53 +02:00
if ( $traitable ) {
2013-08-01 21:20:12 +02:00
if ( $this -> getNode ( 'body' ) instanceof Twig_Node_Body ) {
$nodes = $this -> getNode ( 'body' ) -> getNode ( 0 );
} else {
$nodes = $this -> getNode ( 'body' );
}
if ( ! count ( $nodes )) {
$nodes = new Twig_Node ( array ( $nodes ));
2011-10-05 06:22:53 +02:00
}
foreach ( $nodes as $node ) {
2013-08-01 21:20:12 +02:00
if ( ! count ( $node )) {
continue ;
}
2011-10-05 06:22:53 +02:00
if ( $node instanceof Twig_Node_Text && ctype_space ( $node -> getAttribute ( 'data' ))) {
continue ;
}
if ( $node instanceof Twig_Node_BlockReference ) {
continue ;
}
$traitable = false ;
break ;
}
}
2013-08-01 21:20:12 +02:00
if ( $traitable ) {
return ;
}
2011-10-05 06:22:53 +02:00
$compiler
-> write ( " public function isTraitable() \n " , " { \n " )
-> indent ()
-> write ( sprintf ( " return %s; \n " , $traitable ? 'true' : 'false' ))
-> outdent ()
2013-08-01 21:20:12 +02:00
-> write ( " } \n \n " )
;
}
protected function compileDebugInfo ( Twig_Compiler $compiler )
{
$compiler
-> write ( " public function getDebugInfo() \n " , " { \n " )
-> indent ()
-> write ( sprintf ( " return %s; \n " , str_replace ( " \n " , '' , var_export ( array_reverse ( $compiler -> getDebugInfo (), true ), true ))))
-> outdent ()
2018-05-10 12:24:53 +02:00
-> write ( " } \n \n " )
;
}
protected function compileGetSource ( Twig_Compiler $compiler )
{
$compiler
-> write ( " /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */ \n " )
-> write ( " public function getSource() \n " , " { \n " )
-> indent ()
-> write ( " @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); \n \n " )
-> write ( 'return $this->getSourceContext()->getCode();' )
-> raw ( " \n " )
-> outdent ()
-> write ( " } \n \n " )
;
}
protected function compileGetSourceContext ( Twig_Compiler $compiler )
{
$compiler
-> write ( " public function getSourceContext() \n " , " { \n " )
-> indent ()
-> write ( 'return new Twig_Source(' )
-> string ( $compiler -> getEnvironment () -> isDebug () ? $this -> source -> getCode () : '' )
-> raw ( ', ' )
-> string ( $this -> source -> getName ())
-> raw ( ', ' )
-> string ( $this -> source -> getPath ())
-> raw ( " ); \n " )
-> outdent ()
2011-10-05 06:22:53 +02:00
-> write ( " } \n " )
;
}
2013-08-01 21:20:12 +02:00
protected function compileLoadTemplate ( Twig_Compiler $compiler , $node , $var )
2011-10-05 06:22:53 +02:00
{
if ( $node instanceof Twig_Node_Expression_Constant ) {
$compiler
2018-05-10 12:24:53 +02:00
-> write ( sprintf ( '%s = $this->loadTemplate(' , $var ))
2011-10-05 06:22:53 +02:00
-> subcompile ( $node )
2018-05-10 12:24:53 +02:00
-> raw ( ', ' )
-> repr ( $node -> getTemplateName ())
-> raw ( ', ' )
-> repr ( $node -> getTemplateLine ())
2011-10-05 06:22:53 +02:00
-> raw ( " ); \n " )
;
} else {
2018-05-10 12:24:53 +02:00
throw new LogicException ( 'Trait templates can only be constant nodes.' );
2011-10-05 06:22:53 +02:00
}
}
}
2018-05-10 12:24:53 +02:00
class_alias ( 'Twig_Node_Module' , 'Twig\Node\ModuleNode' , false );