including *.latte templates without caring the directory structure

medhi
Generous Backer | 255
+
+1
-

This is ugly:

{include '../../../menu.latte'}
{* or *}
{embed '../../../menu.latte'}{/embed}

It's so annoying to search how deep in my directory structure I am, and it should not matter, why should I care?
Also, if the parent template is moved upper or lower, these paths stop working.

How about to put all these templates – that are used only to be included – to some predefined directory and then include them without caring about the directory structure?

Last edited by medhi (2020-11-06 22:52)

Rick Strafy
Nette Blogger | 81
+
0
-

So you want all templates that you include somewhere in one directory? It's sounds like very bad joke, projects with folders like Includes or Utils are considered as those with design flaws where author didn't make effort to make better project structure, but it's not always true, usually it's better use something like Article/@Common to have common templates that have to do something with articles.

But on the other hand, it would be cool to define template root, for instance my template root would be here https://github.com/…%40Templates so I could use {embed '/@Layout/Embeds/menu.latte'} anywhere, but until now I didn't have problem with paths, it's very rare when I move latte file to other directory.

Last edited by Rick Strafy (2020-11-06 23:13)

medhi
Generous Backer | 255
+
0
-

I was not proposing any particular solution, but just a general idea to have more pleasant way to include a template.

Now I have something like this in my code:

{embed '../../../../templates/infobox.latte'}
...
{/embed}

Which is… difficult to read at least?

Absolute paths? Maybe, why not :)

dsar
Backer | 53
+
+1
-

IMHO it's not the nette-way.

Why not a menu component that render its own latte placed in the same folder?

Then:

{control menu}

Maybe it's overkilling for just a static menu, but one day you would need more control over it (such as ACL, database stuff, etc…)

medhi
Generous Backer | 255
+
0
-

I am afraid the Control can't be used for my use case, which is to embed a modal window with a full html body, that is different for every use :( You won't pass a big chunk of HTML/latte into a Control.

filsedla
Member | 101
+
+5
-

You can actually define a constant in app/bootstrap.php

define('TEMPLATE_ROOT', __DIR__ . '/templates/@common');

and then in any template use

{include TEMPLATE_ROOT . '/subdir/someRepeatingWidget.latte'}
Šaman
Member | 2666
+
+1
-

medhi wrote:

You won't pass a big chunk of HTML/latte into a Control.

Why? Control has own independent template. Even Presenter is Control.

David Grudl
Nette Core | 8228
+
+2
-

You can set your own root for the Latte and then all “absolute” paths will be relative to this root:

		$this->template->getLatte()->setLoader(
			new Latte\Loaders\FileLoader(__DIR__ . '/templates')
		);

The problem is that Presenter is not ready for this and use absolute paths in methods like formatTemplateFiles(). The easiest solution is therefore to use a variable $root or as he wrote @filsedla define constant.

medhi
Generous Backer | 255
+
0
-

Šaman wrote:

medhi wrote:

You won't pass a big chunk of HTML/latte into a Control.

Why? Control has own independent template. Even Presenter is Control.

Because I need to pass different big chunks of HTML. A modal for example. It has its own template, but always has different body, which is not suitable for control to pass in.

dsar
Backer | 53
+
0
-

This is ugly:

{include '../../../menu.latte'}
{* or *}
{embed '../../../menu.latte'}{/embed}

I had this problem with a layout shared by multiple modules and I have found a way to hide this (not ideal but at least it hides this ugliness).

In your case just create a menu.latte in the same folder with {include ‘../../../menu.latte’}. Then in your latte files you can just use {include menu.latte}.

Last edited by dsar (2021-03-13 09:21)

David Grudl
Nette Core | 8228
+
+5
-

Maybe it would be useful to make some Loader, in which you can add more paths and their aliases, like

'components' => __DIR__ . '/../templates/components',
'layouts' => __DIR__ . '/layouts',
'' => __DIR__ . '/templates',  // default one
...

So if I write {layout 'layouts/main.latte'}, it will resolve it as __DIR__ . '/layouts/main.latte.

Perhaps more paths could be allowed in which it will try to search for a file:

'layouts' => [
	__DIR__ . '/layouts',
	__DIR__ . '/../submodule/layouts',
]
'' => [ ... ]
jdan1131x
Member | 41
+
0
-

sometimes i am away from site code for months.
so i forget, get rusty ..

today i am thinking, to maximize code reuse,
have directory structure:

→ LayoutModule (nothing but @layout.latte and children all imported…no Presenters…)
-->→ @layout.latte
-->-->→ child 1
-->-->→ child n+1 …
-->-->FrontModule
-->-->→ @layout.front.latte (imports @layout.latte above)
-->-->XYZModule
-->-->→ @layout.xyz.latte (imports @layout.latte above)
-->-->N+1…Module
-->-->→ @layout.N+1....latte (imports @layout.latte above)

then i would install ALL children, ALL blocks, ALL defines into LayoutModule and
use existing Latte tools to do so.

my objective is to minimize the number of layout children
and keep them all in one directory.
makes sense without new Loader code or Constant code?
thanks very much,
James

jdan1131x
Member | 41
+
0
-

I setup a LayoutModule directory with all my latte files.

then i setup a TestModule directory with Presenters folder and a TestPresenter.php,
and inside that templates folder I make symbolic link to the @layout.latte file
in the LayoutModule that I need, then make symlinks to the child latte files as needed…
So far, this works fine and seems worth my efforts…

James

jdan1131x
Member | 41
+
0
-

minor adjustment. left real @layout.latte in each module…
only children symlinked…

chemix
Nette Core | 1310
+
0
-

I realy like idea like this:

'components' => __DIR__ . '/../templates/components',
'layouts' => __DIR__ . '/layouts',
'embed' => __DIR__ . '/../templates/embed',
'include' => __DIR__ . '/../templates/include',

with support of

'embed' => [
	__DIR__ . '/../../../vendor/components/templates/default/embed', // priority 2
	__DIR__ . '/../templates/local/embed', // priority 1
]

and next level, maybe, will be possible to use it in template like this with “~”:

    {embed '~embed/embed.cody.feature_v4.latte'
    document: $villa,
    image: $villaImage}
        {block content}
            {include parent}
            {include "~include/include.cody.image-small-gallery.latte", gallery: $villaGallery}
        {/block}
    {/embed}

the first “virtual folder” behind tilda “~” will define “namespace” for template path

Jan Tvrdík
Nette guru | 2595
+
0
-

I see it roughly like this: https://www.youtube.com/watch?…

chemix
Nette Core | 1310
+
0
-

@JanTvrdík why ? it's magic ?

dakur
Member | 493
+
0
-

I agree that writing so much of ../ is error-prone. I have problem with it on every refactoring of directory structure as neither PhpStorm nor static analysis catch it so I end up with error in UI in the end.

Having alias like in node world or in sass is clever solution, but I vote for ~ component resolution only – it's just one char away and we don't want global space pollution again I think. So:

// something => 'src/whatever'

include '~something/template.latte' -> src/whatever/template.latte
include 'something/template.latte' -> ./something/template.latte

Last edited by dakur (2021-05-06 09:24)

David Grudl
Nette Core | 8228
+
0
-

but I vote for ~ component resolution only

👍

Slava.Aurim
Member | 19
+
+4
-

In my humble opinion, the most elegant solution would be to specify the namespace using a colon:

{include 'widgets:social.latte'}

And adding namespaces via FileLoader:

$this->template->getLatte()->getLoader()->addDirectories(['widgets' => '.../templates/widgets']);

Or in config.neon with the help of LatteExtension:

latte:
	scanDirs: #or baseDirs, namespaces, templateDirs , etc.
		root: %appDir%/templates
		widgets: %appDir%/templates/widgets

Last edited by Slava.Aurim (2021-09-15 19:44)

Lulco
Member | 4
+
0
-

@dakur
“neither PhpStorm nor static analysis catch it so I end”

Static analysis can catch it. Check https://github.com/…hpstan-latte

David Grudl
Nette Core | 8228
+
+3
-

I prefer using a function that returns a path, for example, to components. I can add the function to Latte via an extension:

namespace App\UI\Accessory;

use Latte\Extension;

final class LatteExtension extends Extension
{
    public function getFunctions(): array
    {
        return [
            'component' => fn(string $path) => $this->root . '/components/' . $path,
        ];
    }
}

which I will register in the configuration file:

latte:
    extensions:
        - App\UI\Accessory\LatteExtension

Then, in the template, just use:

{include component('menu.latte')}
m.brecher
Generous Backer | 872
+
0
-

@DavidGrudl

For file paths, whether it's {include '....'} or <link href={$basePath.'/....'}, the key feature is IDE autocompletion because manually filling in the file name is tedious and prone to typos.

We need to come up with a smart integrated solution for Latte + Latte plugin by @messour for all types of paths in Latte. This would enable existing IDE features such as:

  • Folder/file name suggestion
  • Built-in file name refactoring
  • Indication of non-existent files

I have some ideas in mind, so I'll try to submit a well-thought-out RFC for discussion.

dkorpar
Member | 136
+
0
-

Would be nice if at least English section of board is on English…

David Grudl
Nette Core | 8228
+
+1
-

@dkorpar I didn't see it, I'll translate it