- Added basic exception remodeling, seaking original template sources.
This commit is contained in:
parent
10632e9f67
commit
1334278e37
|
@ -22,6 +22,8 @@ class Builder
|
||||||
'%USE%' => ( $uses = $context->renderUses() ) ? "use $uses;" : false,
|
'%USE%' => ( $uses = $context->renderUses() ) ? "use $uses;" : false,
|
||||||
'%CLASSNAME%' => $context->className,
|
'%CLASSNAME%' => $context->className,
|
||||||
'%PATHNAME%' => $context->viewPath,
|
'%PATHNAME%' => $context->viewPath,
|
||||||
|
'%FULLPATH%' => $context->filePath,
|
||||||
|
'%TEMPLATE%' => $this->templatePath,
|
||||||
'%EXTENDS%' => $context->extendFrom ? "extends " . static::TEMPLATE_CLASSNAME_PREFIX . static::generateClassUID($context->extendFrom) : '',
|
'%EXTENDS%' => $context->extendFrom ? "extends " . static::TEMPLATE_CLASSNAME_PREFIX . static::generateClassUID($context->extendFrom) : '',
|
||||||
'%EXTENDS_TEMPLATE%' => $context->extendFrom,
|
'%EXTENDS_TEMPLATE%' => $context->extendFrom,
|
||||||
'%CONTENT%' => $compiledSource,
|
'%CONTENT%' => $compiledSource,
|
||||||
|
|
|
@ -5,6 +5,9 @@ namespace %NAMESPACE%;
|
||||||
%USE%
|
%USE%
|
||||||
|
|
||||||
# %PATHNAME%
|
# %PATHNAME%
|
||||||
|
|
||||||
|
if (! class_exists("%NAMESPACE%\%CLASSNAME%", false) ) {
|
||||||
|
|
||||||
class %CLASSNAME% %EXTENDS% {
|
class %CLASSNAME% %EXTENDS% {
|
||||||
public array $blockList = [];
|
public array $blockList = [];
|
||||||
|
|
||||||
|
@ -58,6 +61,21 @@ class %CLASSNAME% %EXTENDS% {
|
||||||
%FUNCTIONS%
|
%FUNCTIONS%
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getSourceLineFromException(\Throwable $ex) : ? int
|
||||||
|
{
|
||||||
|
$sourceFile = file_get_contents("%TEMPLATE%");
|
||||||
|
|
||||||
|
if ( $sourceFile ) {
|
||||||
|
foreach(explode(PHP_EOL, $sourceFile) as $line => $content) {
|
||||||
|
if ( strpos($content, str_replace('$', '%', '$CONTENT$')) !== false ) {
|
||||||
|
return $ex->getLine() - $line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public function __invoke(array $variablesList = []) : string
|
public function __invoke(array $variablesList = []) : string
|
||||||
{
|
{
|
||||||
ob_start();
|
ob_start();
|
||||||
|
@ -66,4 +84,6 @@ class %CLASSNAME% %EXTENDS% {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return [ 'classname' => "%CLASSNAME%", 'namespace' => "%NAMESPACE%", 'extends' => "%EXTENDS_TEMPLATE%" ];
|
}
|
||||||
|
|
||||||
|
return [ 'classname' => "%CLASSNAME%", 'namespace' => "%NAMESPACE%", 'extends' => "%EXTENDS_TEMPLATE%", 'view' => "%FULLPATH%" ];
|
||||||
|
|
|
@ -45,8 +45,6 @@ class Compiler
|
||||||
$this->sourceCode = preg_replace_callback($replace, function ($matches) use (&$context) {
|
$this->sourceCode = preg_replace_callback($replace, function ($matches) use (&$context) {
|
||||||
$matches[2] = trim($matches[2]);
|
$matches[2] = trim($matches[2]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
list($token, $arguments) = array_pad(array_filter(explode(' ', $matches[2], 2), 'strlen'), 2, null);
|
list($token, $arguments) = array_pad(array_filter(explode(' ', $matches[2], 2), 'strlen'), 2, null);
|
||||||
|
|
||||||
$token = trim($token);
|
$token = trim($token);
|
||||||
|
|
|
@ -45,9 +45,9 @@ class SectionToken implements ControlStructure {
|
||||||
|
|
||||||
$order = $options['order'] ?? "count(\$___class__template->sectionList[$name]['$action'])";
|
$order = $options['order'] ?? "count(\$___class__template->sectionList[$name]['$action'])";
|
||||||
|
|
||||||
return "<?php \$___class__template->sectionList[$name] ??= [ 'prepend' => [], 'append' => [], 'default' => [] ];
|
return "<?php \$___class__template->sectionList[$name] ??= [ 'prepend' => [], 'append' => [], 'default' => [] ];".
|
||||||
\$___class__template->sectionList[$name]['$action'][] = [ 'order' => $order, 'callback' => function() use (\$picea, \$___class__template, \$___global_variables, \$___variables) {
|
"\$___class__template->sectionList[$name]['$action'][] = [ 'order' => $order, 'callback' => function() use (\$picea, \$___class__template, \$___global_variables, \$___variables) {".
|
||||||
extract(\$___global_variables); extract(\$___variables, \EXTR_OVERWRITE); ?>";
|
"extract(\$___global_variables); extract(\$___variables, \EXTR_OVERWRITE); ?>";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function printEndSection($context) : string
|
protected function printEndSection($context) : string
|
||||||
|
|
|
@ -0,0 +1,129 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace Twig\Error;
|
||||||
|
|
||||||
|
use Twig\Source;
|
||||||
|
use Twig\Template;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Twig base exception.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* 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
|
||||||
|
* when creating a new instance of this class.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class RenderingError extends \Exception
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* By default, automatic guessing is enabled.
|
||||||
|
*
|
||||||
|
* @param string $message The error message
|
||||||
|
* @param int $lineno The template line where the error occurred
|
||||||
|
* @param Source|null $source The source context where the error occurred
|
||||||
|
*/
|
||||||
|
public function __construct(string $message, Source $source = null, \Exception $previous = null)
|
||||||
|
{
|
||||||
|
parent::__construct('', 0, $previous);
|
||||||
|
|
||||||
|
if (null === $source) {
|
||||||
|
$name = null;
|
||||||
|
} else {
|
||||||
|
$name = $source->getName();
|
||||||
|
$this->sourceCode = $source->getCode();
|
||||||
|
$this->sourcePath = $source->getPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->lineno = $lineno;
|
||||||
|
$this->name = $name;
|
||||||
|
$this->rawMessage = $message;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function generateFromCompiledClass(\Throwable $exception) : self
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
return $exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function readTemplateInformation(): void
|
||||||
|
{
|
||||||
|
$template = null;
|
||||||
|
$templateClass = null;
|
||||||
|
|
||||||
|
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT);
|
||||||
|
foreach ($backtrace as $trace) {
|
||||||
|
if (isset($trace['object']) && $trace['object'] instanceof Template) {
|
||||||
|
$currentClass = \get_class($trace['object']);
|
||||||
|
$isEmbedContainer = 0 === strpos($templateClass, $currentClass);
|
||||||
|
if (null === $this->name || ($this->name == $trace['object']->getTemplateName() && !$isEmbedContainer)) {
|
||||||
|
$template = $trace['object'];
|
||||||
|
$templateClass = \get_class($trace['object']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update template name
|
||||||
|
if (null !== $template && null === $this->name) {
|
||||||
|
$this->name = $template->getTemplateName();
|
||||||
|
}
|
||||||
|
|
||||||
|
// update template path if any
|
||||||
|
if (null !== $template && null === $this->sourcePath) {
|
||||||
|
$src = $template->getSourceContext();
|
||||||
|
$this->sourceCode = $src->getCode();
|
||||||
|
$this->sourcePath = $src->getPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $template || $this->lineno > -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$r = new \ReflectionObject($template);
|
||||||
|
$file = $r->getFileName();
|
||||||
|
|
||||||
|
$exceptions = [$e = $this];
|
||||||
|
while ($e = $e->getPrevious()) {
|
||||||
|
$exceptions[] = $e;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ($e = array_pop($exceptions)) {
|
||||||
|
$traces = $e->getTrace();
|
||||||
|
array_unshift($traces, ['file' => $e->getFile(), 'line' => $e->getLine()]);
|
||||||
|
|
||||||
|
while ($trace = array_shift($traces)) {
|
||||||
|
if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($template->getDebugInfo() as $codeLine => $templateLine) {
|
||||||
|
if ($codeLine <= $trace['line']) {
|
||||||
|
// update template line
|
||||||
|
$this->lineno = $templateLine;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -53,8 +53,13 @@ class FileFetcher
|
||||||
throw new \RuntimeException("Given view file `$fileName` can not be found within given folder list..");
|
throw new \RuntimeException("Given view file `$fileName` can not be found within given folder list..");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getFilePath(string $fileName) : string
|
||||||
|
{
|
||||||
|
return $this->findFile($fileName);
|
||||||
|
}
|
||||||
|
|
||||||
public function getFileContent(string $fileName) : string
|
public function getFileContent(string $fileName) : string
|
||||||
{
|
{
|
||||||
return file_get_contents($this->findFile($fileName));
|
return file_get_contents($this->getFilePath($fileName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,9 @@
|
||||||
namespace Picea;
|
namespace Picea;
|
||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
use Picea\Language\LanguageRegistration;
|
use Picea\Language\LanguageRegistration,
|
||||||
|
Picea\Exception\RenderingError;
|
||||||
|
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
class Picea implements LanguageRegistration
|
class Picea implements LanguageRegistration
|
||||||
|
@ -49,14 +51,32 @@ class Picea implements LanguageRegistration
|
||||||
$this->renderContext($this->context);
|
$this->renderContext($this->context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function renderHtml(string $viewPath, array $variables = [], ?object $proxy = null) : string
|
public function renderHtml(string $viewPath, array $variables = [], ?object $proxy = null) : ? string
|
||||||
{
|
{
|
||||||
if ( null === $object = $this->fetchFromCache($viewPath, $variables, $proxy) ) {
|
if ( null === $object = $this->fetchFromCache($viewPath, $variables, $proxy) ) {
|
||||||
throw new \RuntimeException("An error occured while trying to save a compiled template.");
|
throw new \RuntimeException("An error occured while trying to save a compiled template.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
return $object();
|
return $object();
|
||||||
}
|
}
|
||||||
|
catch(\Throwable $ex) {
|
||||||
|
# Temporary class for an experiment
|
||||||
|
throw new class($object, "An error occurred trying to render HTML view `$viewPath` : " . $ex->getMessage(), 911, $ex) extends \Exception {
|
||||||
|
public function __construct(object $compiledObject, string $message, int $code, \Throwable $previous)
|
||||||
|
{
|
||||||
|
parent::__construct($message, $code, $previous);
|
||||||
|
|
||||||
|
$classContent = include( $previous->getFile() );
|
||||||
|
|
||||||
|
if ( is_array($classContent) ) {
|
||||||
|
$this->file = $classContent['view'];
|
||||||
|
$this->line = $compiledObject->getSourceLineFromException($previous);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method used by Block and View tokens
|
* Method used by Block and View tokens
|
||||||
|
@ -207,6 +227,7 @@ class Picea implements LanguageRegistration
|
||||||
$compiled = $this->compileSource($this->fileFetcher->getFileContent($viewPath));
|
$compiled = $this->compileSource($this->fileFetcher->getFileContent($viewPath));
|
||||||
$context = $compiled['context'];
|
$context = $compiled['context'];
|
||||||
$context->viewPath = $viewPath;
|
$context->viewPath = $viewPath;
|
||||||
|
$context->filePath = $this->fileFetcher->getFilePath($viewPath);
|
||||||
$context = $builder->build($compiled['context'], $compiled['source']) ;
|
$context = $builder->build($compiled['context'], $compiled['source']) ;
|
||||||
$context->classPath = $tmpFolder . DIRECTORY_SEPARATOR . $context->className . ".php";
|
$context->classPath = $tmpFolder . DIRECTORY_SEPARATOR . $context->className . ".php";
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue