thephpleague / plates

Native PHP template system
https://platesphp.com
MIT License
1.47k stars 180 forks source link

addFolder is not what i want: how do i allow searching in more then 1 default directory? #59

Closed badpenguin closed 6 years ago

badpenguin commented 9 years ago

I've an array of 4 directories, is it possible to have them as default search paths instead of just 1 ?

badpenguin commented 9 years ago

Ok i can rewrite my patch to be more general using its own propery and set/get funcs.

I need user's templates and package's templates to override the core framework's template (i.e. the default directory). So, i need to provide the engine a default directory search order like this: $dir=array( 'my app dir', 'pkg1 dir', 'pkg2 dir', 'framework dir' );

So, if the framework provides loginform.tpl the package or the user can ovverride it just creating a modified file in their directory.

I undestand addFolder() is not what you want.

Can i add a new set/get directories to be used in addition to default directory?

That's the only missing point for me to use this template engine in replace of Twig.

gmazzap commented 9 years ago

Hi @badpenguin,

I can understand you because in the days I wanted to use Plates as Twig replacement this was something I had to face too. (And this is the reason in Foil folders are handled like so).

However, at that time I used an approach that allowed me use multiple folders without to modify Plates.

First of all I created a class to hold and search folder paths, something like:

namespace BadPinguin;

class Folders
{
    private $folders = array();

    public function __construct(array $folders)
    {
        $ds = DIRECTORY_SEPARATOR;
        $this->folders = array_walk($folders, function($folder) {
            return rtrim(preg_replace('~[/\\]+~',$ds, $folder), $ds).$ds;
        });
    }

    public function find($file)
    {
        foreach($this->folders as $folder) {
            $path = $folder.ltrim($file,'\\/');
            if (is_file($path)) {
                return $path;
            }
        }

        return false;
    }
}

After that, I created a function that searches in folders using class above and returns a Plates template instance:

namespace BadPinguin;

function getTemplate(\League\Plates\Engine $engine, Folders $folders, $name)
{
    $found = $folders->find($name);
    if (!$found) {
        throw new \InvalidArgumentException(
            'A template named "' . $name . '" was not found in any folder.';
        );
    }
    $info = pathinfo($found);
    $engine->setDirectory($info['dirname']); // set engine folder "on the fly"

    return new \League\Plates\Template($engine, $info['filename']));
}

And finally, inside controllers:

$folders = new BadPinguin\Folders(array(
    '/path/to/files/one',
    '/path/to/files/two',
    '/path/to/files/three',
    '/path/to/files/four',
));
$engine = new League\Plates\Engine(null, 'tpl'); // no default folder
$template = BadPinguin\getTemplate($engine, $folders, 'home.tpl');

return $template->render($data);
badpenguin commented 9 years ago

Thank you very much! I'm developing my own little framework and having a PHP native template system is essential to keep it small. I work a lot on small VPS and cannot afford to use the huges framework dinosaurs out there.

badpenguin commented 9 years ago

Little problem... your solution will not work with fetch(), layout() and other function used within the template.

This will only work for the initial template.

This is not my case :/

gmazzap commented 9 years ago

I know. Extend template class with your own where you override layout and fetch.

badpenguin commented 9 years ago

Its easy for me to survive with my forked repository then :)

gmazzap commented 9 years ago

Sure? Maintain a parallel forked repo is never easy. Thinks to all upgrades, new feautures and bug fixes may happen on main repo. You'll lost them or you have to integrate them one by one, checking that they do not break your fork, because of your edits. It's a way to go? Sure. But I'd stay away to say it's easy ;)

badpenguin commented 9 years ago

Wow all this drama for exactly 6 lines of code :))

gmazzap commented 9 years ago

That's exaclty the problem: maintain a forked repo just for 6 lines of code. You said you want to use the package for a custom framework. So I assume you want to keep it updated. Next time someone post a bugfix to Plates, I assume you want the bug fixed in your repo too.

How to do that? You have to watch Plates, look at any new commit and see if is the case to implement it in your repo too. And if so, be sure it does not overwrite your edits. It worth do that to just modify 6 lines of code?

Sure you can ignore any new Plates commit, and always keep that frozen version, or maybe develop your fork in parallel... but again, It worth do that to just modify 6 lines of code?

If that 6 lines of code are the only issue you have with Plates, how much time and effort you can save if you spent one hour in develop a solution that can work with Plates as is and then just composer update when needed?

Not to mention if you plan to share your framework. What you'll do, put your forked repo in Packagist? Or you'll ask your users to set repository settings in composer.json? And all that for just 6 lines of customization?

Please note that I'm not taking the role of Plates lawyer, in fact, I am someone who has done a lot of work to write a completely new package to replace Plates, but the issues I had with Plates were quite a lot...

badpenguin commented 9 years ago

I'm waiting for him to know if he wants that extra features or not.

reinink commented 9 years ago

I'm open to adding multiple folder support to Plates. Currently enjoying time with family, but will follow up with more details tomorrow.

gmazzap commented 9 years ago

My honest opinion is that it can't be done with full backward compatibility.

Currently is possible to fallback a template to "main" folder if not found in required one.

When enabled, if a folder template is missing, Plates will automatically fallback and look for a template with the same name in the default folder.When enabled, if a folder template is missing, Plates will automatically fallback and look for a template with the same name in the default folder.

(quote from here)

So is possible that people that have their templates folder structure built upon current Plates version can see a template loaded in place of another because a template that should fallback to main folder, will fallback to another folder.

I feel it's a great addon for Plates, but I don't think is possible before version 4.

badpenguin commented 9 years ago

Thanks @reinink ! Wich is your preferred public method name for this? What about i call it SetAdditionalFolders or SetExtraFolders ?

reinink commented 9 years ago

Leave this with me to implement, I want to think through this carefully as to prevent any backwards compatibility breaks as @Giuseppe-Mazzapica is suggesting could happen.

Honestly, I'm seeing this as simple as having the option to pass an array of default directories, instead of just a string. This also prevents any breaks, since existing could will continue working exactly as it is.

// Set default directories when creating engine
$templates = new League\Plates\Engine([
    '/path/to/templates',
    '/path/to/more/templates',
    '/path/to/other/templates',
]);

// Set default directories with setter method
$templates->setDirectory([
    '/path/to/templates',
    '/path/to/more/templates',
    '/path/to/other/templates',
]);

This keeps this functionality totally separate from the existing folders functionality. In fact, the folder fallbacks will still work if multiple default directories are set, it will simply look in more than one directory at that point.

@badpenguin Does that sound like it would solve your issue?

badpenguin commented 9 years ago

Yes, do you want me to code the patch this way?

reinink commented 9 years ago

If you want to give it a try, by all means! You'll have to tweak Engine.php, Template/Name.php and Template/Directory, hopefully that's it.

ragboyjr commented 7 years ago

I think this falls under the same feature/system as #130 and #79, but will keep it around to try and get a system to work for all 3 types.

drnkwati commented 7 years ago

Hi guys was this feature added. Should we expect a patch soon?. I need this feature Thanks

ragboyjr commented 6 years ago

Closing in favor of #170

ipranjal commented 6 years ago

I was building Plates support module for www.github.com/scrawler-php/scrawler that module would allow plates to be used as template engine for scrawler but i need to make sure plate also registers templates provided by other modules hence need to register multiple directories

ragboyjr commented 6 years ago

@physcocode I'm currently working on v4 which will include a more powerful naming strategy system. This is one of the features the naming strategies could support.