Open zorca opened 8 years ago
Well, there exists a major problem with dynamic includes.
You'd need to also compile all files that could be possibly included and have them in the same structure to give you the ability to use PHP's include
inside the generated PHTML to include files dynamically.
What include does right now is compiling the included file (no matter if it's jade or something else) and directly render it into the generated PHTML file (Which is the only way to generate good stand-alone PHTML files)
I will tell you how I solved it in a CMS I'm currently writing. I'm pre-rendering included modules.
As an example, I have menues that can use different templates
id | name | template
----------------------------------
1 | main-menu | default
2 | footer-menu | foot
When I want to use them inside Jade, I render them first and pass the rendered HTML to Jade
$menu = $menuDb->findOne(1);
$menuHtml = $renderer->render('menues/menu-'.$menu->template, ['menu' => $menu]);
$html = $renderer->render('one-column', ['menuHtml' => $menuHtml]);
echo $html;
This happens through some abstraction of course.
In one-column.jade
you'd have
doctype html
html
head
title My Title
body
nav!= $menuHtml
This also gives you neater caching-possibilities than dynamic includes would.
Notice the !
to avoid HTML-escaping.
Another approach would be to use some kind of static helper, function or closure inside jade
echo $renderer->render('one-column', [
'renderMenu' => function ($name, array $args = null) use ($renderer) {
return $renderer->render('menues/menu-'.$name, $args);
}
]);
//or
class MenuHelper
{
public static function render($name, array $args = null)
{
$renderer = StaticSource::getStaticRenderer();
return $renderer->render('menues/menu-'.$name, $args);
}
}
You could use those two like this
nav!= $renderMenu($menuName)
//or
nav!= MenuHelper::render($menuName)
Thanks for the detailed response! I'm working on a simple CMS that uses a flat-files as a database. I like Grav CMS, but it is too complicated to use. Other options considered are also not very fit. And I am interested in your developments in this direction.
My temporary solution for dynamic includes:
mixin sections(...sectionsList)
each $sectionsItem, $sectionsKey in $sectionsList
section(id=$sectionsItem)
-
$sectionsItemFile = APP . 'sections/_' . $sectionsKey . '.jade';
if(file_exists($sectionsItemFile)) $sectionsItemContent = file_get_contents($sectionsItemFile);
$__value = isset($sectionsItemContent) ? $sectionsItemContent : false;
$__jade = new \Tale\Jade\Renderer();
echo $__jade->compile($__value, '"', true); unset($__value); unset($__jade);
I am actually thinking about a way I could realize dynamic includes by re-using the compiler inside the jade file.
This would not be possible for jade files generated with the standAlone
-option, though, since those are designed to run as single PHP files.
Is there a way I can get the include path to work from a variable string?
The value of the string is not going to be "dynamic", as in every parse the result should be the same.
Ideally this:
include my-path/template.jade
Would work the same as something like this:
- $includePath = 'my-path/template.jade';
include $includePath
The use case is for these sorts of component mixins:
mixin generic-content($includePath)
.generic-content
include $includePath
section
+special-heading('First Section')
+generic-content('content/first-section.jade')
section
+special-heading('Other section')
+generic-content('content/other-section.jade')
In such a contrived example the value is less obvious. We store all our content in a JSON style PHP array as component mixin key/value props, and blobs of HTML are difficult to manage in a string value.
I will implement dynamic includes as soon as I got time for it, they will behave just like you expect it.
In the mean-time, roll your own!
$args = [/*...*/];
$args['includeFile'] = function($path) use ($renderer, &$args) {
return $renderer->render($path, $args)
};
$renderer->render('index', $args);
mixin generic-content($includePath)
.generic-content
!= $includeFile($includePath)
section
+special-heading('First Section')
+generic-content('content/first-section')
section
+special-heading('Other section')
+generic-content('content/other-section')
This doesn't get invalid when I implement the actual dynamic includes, you can simply replace them slowly later on.
The problem is that at the point where the Compiler does the actual include
(All included/extended files get parsed in the same compilation process because of things like shared blocks and variable scopes), variables aren't evaluated yet. The compiler neither knows which variables are there nor does it know which values they might have and it has no way of finding out.
You might think include #{$dynamicPath}.jade
could render to something like <?php include($dynamicPath.'.phtml'); ?>
(and it could, easily), but the problems I tried to explain above still exists
Regardless on where or how you set that variable, the compiler will never know what value it has. Only the runtime PHTML does. It would need a way to pre-compile all possible files that could be included in there so that the include
-line there actually includes PHTML-templates that exist and are renderered correctly already. Even if the value is always the same, it doesn't change the fact that the compiler doesn't know what it is.
I will probably fall back to the method I've shown you here (Just in a hard-coded, stable and standard way) if the include contains an interpolation and it will only work outside stand_alone
-mode.
Hi, Torben! I create a frontend tool for building OnePage websites without using Gulp, PHP only. And I need dynamic includes for sections, which are located in a specific folder, named app/sections. The number and names of include files is unknown, but they will be called in accordance with the mask: (section-number)(section-name).jade. Whether such inclusion in the current version of your library? I would be grateful for a code example.