PHP-Foundation
PHP-Foundation copied to clipboard
Precompile templates error with filter.
I try some test but I don't understand why is generated this error.
Delight\Foundation\Throwable\TemplateSyntaxError: Unknown "ifFileExist" filter. in file Z:\ws\www\foundation\vendor\delight-im\foundation-core\src\TemplateManager.php on line 167
Stack trace:
1. Delight\Foundation\Throwable\TemplateSyntaxError->() Z:\ws\www\foundation\vendor\delight-im\foundation-core\src\TemplateManager.php:167
2. Twig_Error_Syntax->() Z:\ws\www\foundation\views\backend\default\catalog\includes\javascript\prices.html.twig:16
3. Twig_ExpressionParser->getFilterNodeClass() Z:\ws\www\foundation\vendor\twig\twig\lib\Twig\ExpressionParser.php:484
4. Twig_ExpressionParser->parseFilterExpressionRaw() Z:\ws\www\foundation\vendor\twig\twig\lib\Twig\ExpressionParser.php:469
5. Twig_ExpressionParser->parseFilterExpression() Z:\ws\www\foundation\vendor\twig\twig\lib\Twig\ExpressionParser.php:323
6. Twig_ExpressionParser->parsePostfixExpression() Z:\ws\www\foundation\vendor\twig\twig\lib\Twig\ExpressionParser.php:215
7. Twig_ExpressionParser->parsePrimaryExpression() Z:\ws\www\foundation\vendor\twig\twig\lib\Twig\ExpressionParser.php:102
8. Twig_ExpressionParser->getPrimary() Z:\ws\www\foundation\vendor\twig\twig\lib\Twig\ExpressionParser.php:55
9. Twig_ExpressionParser->parseExpression() Z:\ws\www\foundation\vendor\twig\twig\lib\Twig\TokenParser\If.php:33
10. Twig_TokenParser_If->parse() Z:\ws\www\foundation\vendor\twig\twig\lib\Twig\Parser.php:192
11. Twig_Parser->subparse() Z:\ws\www\foundation\vendor\twig\twig\lib\Twig\Parser.php:105
12. Twig_Parser->parse() Z:\ws\www\foundation\vendor\twig\twig\lib\Twig\Environment.php:716
13. Twig_Environment->parse() Z:\ws\www\foundation\vendor\twig\twig\lib\Twig\Environment.php:774
14. Twig_Environment->compileSource() Z:\ws\www\foundation\vendor\twig\twig\lib\Twig\Environment.php:452
15. Twig_Environment->loadTemplate() Z:\ws\www\foundation\vendor\delight-im\foundation-core\src\TemplateManager.php:161
16. Delight\Foundation\TemplateManager->precompile() Z:\ws\www\foundation\vendor\delight-im\foundation-core\src\App.php:931
17. Delight\Foundation\App->precompileTemplates() Z:\ws\www\foundation\index.php:111
I created this filter after issue #14 my problem was to check if a lang file exist if not use a fallback file. Because is in Template I prefered to use this solution and not file exist for directory traversal attacks.
MY FILTER
$app->getTemplateManager()->addFilter('ifFileExist', function($file) {
$real_base = realpath('public');
$check_file = $real_base . $file;
$real_file = realpath($check_file);
if ($real_file === false || strpos($real_file, $real_base) !== 0) {
return false;
} else {
return true;
}
});
The if condition in template where is indicated the error
{% set qb_lang = '/assets/querybuilder/i18n/query-builder.'~ session.EZ_LANG ~'.js' %}
{% if qb_lang | ifFileExist %}
<script src="{{ app.url('/assets/querybuilder/i18n/query-builder.'~ session.EZ_LANG ~'.js') }}"></script>
{% else %}
<script src="{{ app.url('/assets/querybuilder/i18n/query-builder.'~ session.EZ_FALLBACK_LANG ~'.js') }}"></script>
{% endif %}
Seems that doesn't like this syntax
{% if qb_lang | ifFileExist %} (Line 16)
Thanks.
Thank you!
When not trying to precompile templates but viewing your application in the browser, as usual, the filter works, doesn’t it? So it’s really not that something is wrong with the filter or the way you defined it.
I guess this must then be because the filter is not yet defined when the framework precompiles the templates for you. That step is executed in the index.php from the parent directory, while you have probably defined the filter in the index.php of the child directory or any other class or file loaded there.
What you did is correct, the problem is in this framework. You could temporarily move your filter definition to the index.php in the parent directory (before the code that precompiles the templates). But this is not a real solution because that file is not supposed to contain your custom application code. As a permanent fix, we have to find something else.
Thank you for your fast reply!
Yes in the application the filter work and I suspected that the precompile was called before but I didn't check where exactly thanks for your link to show me where.
By the way I'll wait your fix because not just need to move the filter in parent but the class init should be moved too so the index.php in child directory become senseless.
Not sure if you should really wait for a fix, because we cannot give any time estimate right now.
Are you sure you really need to move all your definitions and classes? You should make your classes compatible with autoload. If you do this, it’s not important where your classes are loaded first.
Any class in /app will be available via autoloading if you declare namespace App; at the top and the filename is the class name with the PHP extension.
As for this issue here, I see two possible solutions:
- Processing the CLI commands not before processing your
/app/index.phpwith all routes and custom application codes, but after. At that point, all filters, globals, functions and classes will be available. But this doesn’t work if youexitsomewhere in your custom application code (that is executed), or if a route is executed that should not be run on the CLI. - Splitting
/app/index.phpinto/app/global.php, where you can put filter definitions, global functions, etc., and which is executed before the CLI commands are processed, and/app/routes.php, which is executed after the CLI commands are processed, and which can contain your normal route definitions (and other custom application code).
Thanks!
I'll try to read well and understand your 2 solutions and make some test hope that I fix because I didn't get what do you mean with
Are you sure you really need to move all your definitions and classes? You should make your classes compatible with autoload. If you do this, it’s not important where your classes are loaded first.
I just split classes because the app is big but I think that I followed your directive How To manage the Route and Class definition.
app/index.php
use Delight\Foundation\App;
require ('/routes/backend.php');
$app->setStatus(404);
$app->redirect('/foundation/error?code=404');
app/routes/backend.php
use Delight\Foundation\App;
$app->get('/foundation/dashboard', ['\App\Controllers\Backend\Core\Dashboard', 'getDashboard']);
app/controllers/backend/core/dashboard.php
namespace App\Controllers\Backend\Core;
use Delight\Foundation\App;
class Dashboard {
public static function getDashboard(App $app) {
echo $app->view('/backend/'. $_SESSION['BE_THEME'] .'/core/dashboard.html.twig', [...]);
}
}
Now even if I add filter function on top of index.php show me the error because the template precompiled is before in parent index.php so where is my different declaration ?
Any class in /app will be available via autoloading if you declare namespace App; at the top and the filename is the class name with the PHP extension.
Your code looks good.
Look into the index.php in the parent directory, just before the CLI commands are handled:
https://github.com/delight-im/PHP-Foundation/blob/42ee0cf7ac856c4a96039336d628a752432f672e/index.php#L106-L108
Right there, in line 107, simply insert
require __DIR__ . '/app/global.php';
and then create a new global.php in your /app/ folder right next to your index.php.
Now move the definition of the filter from index.php to global.php.
Does that work?
Sorry for long the delay of my answer, but I was working on other part.
For make this test is not so much fast and simple because I don't have only 1 filter but different Filter, function and Global. Than I should to change some constants.
If this is the final solution and this is the only way so I'll change all the structure.
Thanks.
Anyway as a temp test I initialized everything before and work.
Thanks, good to know!
Unfortunately, this is still the only two solutions I can imagine:
* Processing the CLI commands _not before_ processing your `/app/index.php` with all routes and custom application codes, but _after_. At that point, all filters, globals, functions and classes will be available. But this doesn’t work if you `exit` somewhere in your custom application code (that is executed), or if a route is executed that should not be run on the CLI. * Splitting `/app/index.php` into `/app/global.php`, where you can put filter definitions, global functions, etc., and which is executed _before_ the CLI commands are processed, and `/app/routes.php`, which is executed after the CLI commands are processed, and which can contain your normal route definitions (and other custom application code).
As I have explained the second solution already, let’s talk about the first solution and what you’d need to do:
In /index.php, move require __DIR__ . '/app/index.php'; (and its comment) before the larger block starting with if ($app->isClientCli() || $app->isClientLoopback()) { – that’s all. But if your index route (GET /) is then executed when running on the CLI, you could get results that you don’t want, e.g. HTML output on the CLI. As it is a GET request, it should not have any side effects.