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 .
*/
/**
* Twig base exception .
*
2013-08-01 21:20:12 +02:00
* This exception class and its children must only be used when
* an error occurs during the loading of a template , when a syntax error
* is detected in a template , or when rendering a template . Other
* errors must use regular PHP exception classes ( like when the template
* cache directory is not writable for instance ) .
*
* To help debugging template issues , this class tracks the original template
* name and line where the error occurred .
*
* Whenever possible , you must set these information ( original template name
* and line number ) yourself by passing them to the constructor . If some or all
* these information are not available from where you throw the exception , then
* this class will guess them automatically ( when the line number is set to - 1
2018-05-10 12:24:53 +02:00
* and / or the name is set to null ) . As this is a costly operation , this
* can be disabled by passing false for both the name and the line number
2013-08-01 21:20:12 +02:00
* when creating a new instance of this class .
*
* @ author Fabien Potencier < fabien @ symfony . com >
2011-10-05 06:22:53 +02:00
*/
class Twig_Error extends Exception
{
protected $lineno ;
2018-05-10 12:24:53 +02:00
// to be renamed to name in 2.0
2011-10-05 06:22:53 +02:00
protected $filename ;
protected $rawMessage ;
protected $previous ;
2018-05-10 12:24:53 +02:00
private $sourcePath ;
private $sourceCode ;
2011-10-05 06:22:53 +02:00
/**
* Constructor .
*
2018-05-10 12:24:53 +02:00
* Set both the line number and the name to false to
2013-08-01 21:20:12 +02:00
* disable automatic guessing of the original template name
* and line number .
*
* Set the line number to - 1 to enable its automatic guessing .
2018-05-10 12:24:53 +02:00
* Set the name to null to enable its automatic guessing .
2013-08-01 21:20:12 +02:00
*
* By default , automatic guessing is enabled .
*
2018-05-10 12:24:53 +02:00
* @ param string $message The error message
* @ param int $lineno The template line where the error occurred
* @ param Twig_Source | string | null $source The source context where the error occurred
* @ param Exception $previous The previous exception
2011-10-05 06:22:53 +02:00
*/
2018-05-10 12:24:53 +02:00
public function __construct ( $message , $lineno = - 1 , $source = null , Exception $previous = null )
2011-10-05 06:22:53 +02:00
{
2018-05-10 12:24:53 +02:00
if ( null === $source ) {
$name = null ;
} elseif ( ! $source instanceof Twig_Source ) {
// for compat with the Twig C ext., passing the template name as string is accepted
$name = $source ;
} else {
$name = $source -> getName ();
$this -> sourceCode = $source -> getCode ();
$this -> sourcePath = $source -> getPath ();
}
if ( PHP_VERSION_ID < 50300 ) {
2013-08-01 21:20:12 +02:00
$this -> previous = $previous ;
parent :: __construct ( '' );
} else {
parent :: __construct ( '' , 0 , $previous );
2011-10-05 06:22:53 +02:00
}
$this -> lineno = $lineno ;
2018-05-10 12:24:53 +02:00
$this -> filename = $name ;
2013-08-01 21:20:12 +02:00
2018-05-10 12:24:53 +02:00
if ( - 1 === $lineno || null === $name || null === $this -> sourcePath ) {
2013-08-01 21:20:12 +02:00
$this -> guessTemplateInfo ();
}
2011-10-05 06:22:53 +02:00
$this -> rawMessage = $message ;
$this -> updateRepr ();
}
/**
* Gets the raw message .
*
* @ return string The raw message
*/
public function getRawMessage ()
{
return $this -> rawMessage ;
}
/**
2018-05-10 12:24:53 +02:00
* Gets the logical name where the error occurred .
*
* @ return string The name
2011-10-05 06:22:53 +02:00
*
2018-05-10 12:24:53 +02:00
* @ deprecated since 1.27 ( to be removed in 2.0 ) . Use getSourceContext () instead .
2011-10-05 06:22:53 +02:00
*/
public function getTemplateFile ()
{
2018-05-10 12:24:53 +02:00
@ trigger_error ( sprintf ( 'The "%s" method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.' , __METHOD__ ), E_USER_DEPRECATED );
2011-10-05 06:22:53 +02:00
return $this -> filename ;
}
/**
2018-05-10 12:24:53 +02:00
* Sets the logical name where the error occurred .
*
* @ param string $name The name
2011-10-05 06:22:53 +02:00
*
2018-05-10 12:24:53 +02:00
* @ deprecated since 1.27 ( to be removed in 2.0 ) . Use setSourceContext () instead .
2011-10-05 06:22:53 +02:00
*/
2018-05-10 12:24:53 +02:00
public function setTemplateFile ( $name )
2011-10-05 06:22:53 +02:00
{
2018-05-10 12:24:53 +02:00
@ trigger_error ( sprintf ( 'The "%s" method is deprecated since version 1.27 and will be removed in 2.0. Use setSourceContext() instead.' , __METHOD__ ), E_USER_DEPRECATED );
$this -> filename = $name ;
$this -> updateRepr ();
}
/**
* Gets the logical name where the error occurred .
*
* @ return string The name
*
* @ deprecated since 1.29 ( to be removed in 2.0 ) . Use getSourceContext () instead .
*/
public function getTemplateName ()
{
@ trigger_error ( sprintf ( 'The "%s" method is deprecated since version 1.29 and will be removed in 2.0. Use getSourceContext() instead.' , __METHOD__ ), E_USER_DEPRECATED );
return $this -> filename ;
}
/**
* Sets the logical name where the error occurred .
*
* @ param string $name The name
*
* @ deprecated since 1.29 ( to be removed in 2.0 ) . Use setSourceContext () instead .
*/
public function setTemplateName ( $name )
{
@ trigger_error ( sprintf ( 'The "%s" method is deprecated since version 1.29 and will be removed in 2.0. Use setSourceContext() instead.' , __METHOD__ ), E_USER_DEPRECATED );
$this -> filename = $name ;
$this -> sourceCode = $this -> sourcePath = null ;
2011-10-05 06:22:53 +02:00
$this -> updateRepr ();
}
/**
* Gets the template line where the error occurred .
*
2018-05-10 12:24:53 +02:00
* @ return int The template line
2011-10-05 06:22:53 +02:00
*/
public function getTemplateLine ()
{
return $this -> lineno ;
}
/**
* Sets the template line where the error occurred .
*
2018-05-10 12:24:53 +02:00
* @ param int $lineno The template line
2011-10-05 06:22:53 +02:00
*/
public function setTemplateLine ( $lineno )
{
$this -> lineno = $lineno ;
$this -> updateRepr ();
}
2018-05-10 12:24:53 +02:00
/**
* Gets the source context of the Twig template where the error occurred .
*
* @ return Twig_Source | null
*/
public function getSourceContext ()
{
return $this -> filename ? new Twig_Source ( $this -> sourceCode , $this -> filename , $this -> sourcePath ) : null ;
}
/**
* Sets the source context of the Twig template where the error occurred .
*/
public function setSourceContext ( Twig_Source $source = null )
{
if ( null === $source ) {
$this -> sourceCode = $this -> filename = $this -> sourcePath = null ;
} else {
$this -> sourceCode = $source -> getCode ();
$this -> filename = $source -> getName ();
$this -> sourcePath = $source -> getPath ();
}
$this -> updateRepr ();
}
2013-08-01 21:20:12 +02:00
public function guess ()
{
$this -> guessTemplateInfo ();
$this -> updateRepr ();
}
2011-10-05 06:22:53 +02:00
/**
* For PHP < 5.3 . 0 , provides access to the getPrevious () method .
*
2013-08-01 21:20:12 +02:00
* @ param string $method The method name
* @ param array $arguments The parameters to be passed to the method
2011-10-05 06:22:53 +02:00
*
* @ return Exception The previous exception or null
2013-08-01 21:20:12 +02:00
*
* @ throws BadMethodCallException
2011-10-05 06:22:53 +02:00
*/
public function __call ( $method , $arguments )
{
if ( 'getprevious' == strtolower ( $method )) {
return $this -> previous ;
}
throw new BadMethodCallException ( sprintf ( 'Method "Twig_Error::%s()" does not exist.' , $method ));
}
2018-05-10 12:24:53 +02:00
public function appendMessage ( $rawMessage )
{
$this -> rawMessage .= $rawMessage ;
$this -> updateRepr ();
}
/**
* @ internal
*/
2011-10-05 06:22:53 +02:00
protected function updateRepr ()
{
$this -> message = $this -> rawMessage ;
2018-05-10 12:24:53 +02:00
if ( $this -> sourcePath && $this -> lineno > 0 ) {
$this -> file = $this -> sourcePath ;
$this -> line = $this -> lineno ;
return ;
}
2011-10-05 06:22:53 +02:00
$dot = false ;
if ( '.' === substr ( $this -> message , - 1 )) {
$this -> message = substr ( $this -> message , 0 , - 1 );
$dot = true ;
}
2018-05-10 12:24:53 +02:00
$questionMark = false ;
if ( '?' === substr ( $this -> message , - 1 )) {
$this -> message = substr ( $this -> message , 0 , - 1 );
$questionMark = true ;
}
2013-08-01 21:20:12 +02:00
if ( $this -> filename ) {
if ( is_string ( $this -> filename ) || ( is_object ( $this -> filename ) && method_exists ( $this -> filename , '__toString' ))) {
2018-05-10 12:24:53 +02:00
$name = sprintf ( '"%s"' , $this -> filename );
2013-08-01 21:20:12 +02:00
} else {
2018-05-10 12:24:53 +02:00
$name = json_encode ( $this -> filename );
2013-08-01 21:20:12 +02:00
}
2018-05-10 12:24:53 +02:00
$this -> message .= sprintf ( ' in %s' , $name );
2011-10-05 06:22:53 +02:00
}
2013-08-01 21:20:12 +02:00
if ( $this -> lineno && $this -> lineno >= 0 ) {
2011-10-05 06:22:53 +02:00
$this -> message .= sprintf ( ' at line %d' , $this -> lineno );
}
if ( $dot ) {
$this -> message .= '.' ;
}
2018-05-10 12:24:53 +02:00
if ( $questionMark ) {
$this -> message .= '?' ;
}
2011-10-05 06:22:53 +02:00
}
2018-05-10 12:24:53 +02:00
/**
* @ internal
*/
2013-08-01 21:20:12 +02:00
protected function guessTemplateInfo ()
2011-10-05 06:22:53 +02:00
{
2013-08-01 21:20:12 +02:00
$template = null ;
2013-09-19 08:08:25 +02:00
$templateClass = null ;
2013-08-01 21:20:12 +02:00
2018-05-10 12:24:53 +02:00
if ( PHP_VERSION_ID >= 50306 ) {
2013-08-01 21:20:12 +02:00
$backtrace = debug_backtrace ( DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT );
} else {
$backtrace = debug_backtrace ();
2011-10-05 06:22:53 +02:00
}
2013-08-01 21:20:12 +02:00
foreach ( $backtrace as $trace ) {
if ( isset ( $trace [ 'object' ]) && $trace [ 'object' ] instanceof Twig_Template && 'Twig_Template' !== get_class ( $trace [ 'object' ])) {
2013-09-19 08:08:25 +02:00
$currentClass = get_class ( $trace [ 'object' ]);
$isEmbedContainer = 0 === strpos ( $templateClass , $currentClass );
if ( null === $this -> filename || ( $this -> filename == $trace [ 'object' ] -> getTemplateName () && ! $isEmbedContainer )) {
2013-08-01 21:20:12 +02:00
$template = $trace [ 'object' ];
2013-09-19 08:08:25 +02:00
$templateClass = get_class ( $trace [ 'object' ]);
2013-08-01 21:20:12 +02:00
}
2011-10-05 06:22:53 +02:00
}
2013-08-01 21:20:12 +02:00
}
2011-10-05 06:22:53 +02:00
2018-05-10 12:24:53 +02:00
// update template name
2013-08-01 21:20:12 +02:00
if ( null !== $template && null === $this -> filename ) {
$this -> filename = $template -> getTemplateName ();
}
2011-10-05 06:22:53 +02:00
2018-05-10 12:24:53 +02:00
// update template path if any
if ( null !== $template && null === $this -> sourcePath ) {
$src = $template -> getSourceContext ();
$this -> sourceCode = $src -> getCode ();
$this -> sourcePath = $src -> getPath ();
}
2013-08-01 21:20:12 +02:00
if ( null === $template || $this -> lineno > - 1 ) {
return ;
}
2011-10-05 06:22:53 +02:00
2013-08-01 21:20:12 +02:00
$r = new ReflectionObject ( $template );
$file = $r -> getFileName ();
2011-10-05 06:22:53 +02:00
2013-08-01 21:20:12 +02:00
$exceptions = array ( $e = $this );
while (( $e instanceof self || method_exists ( $e , 'getPrevious' )) && $e = $e -> getPrevious ()) {
$exceptions [] = $e ;
}
while ( $e = array_pop ( $exceptions )) {
$traces = $e -> getTrace ();
2018-05-10 12:24:53 +02:00
array_unshift ( $traces , array ( 'file' => $e -> getFile (), 'line' => $e -> getLine ()));
2013-08-01 21:20:12 +02:00
while ( $trace = array_shift ( $traces )) {
if ( ! isset ( $trace [ 'file' ]) || ! isset ( $trace [ 'line' ]) || $file != $trace [ 'file' ]) {
continue ;
2011-10-05 06:22:53 +02:00
}
2013-08-01 21:20:12 +02:00
foreach ( $template -> getDebugInfo () as $codeLine => $templateLine ) {
if ( $codeLine <= $trace [ 'line' ]) {
// update template line
$this -> lineno = $templateLine ;
return ;
}
2011-10-05 06:22:53 +02:00
}
}
}
}
}
2018-05-10 12:24:53 +02:00
class_alias ( 'Twig_Error' , 'Twig\Error\Error' , false );
class_exists ( 'Twig_Source' );