How do you use absolute paths with Volt for Views, Layouts, Partials and Extends

Hi,

Can you tell me if its possible to set absolute paths when using volt partials and similar?

This works {{ partial("../../common/layouts/master/includes/leaderboard/tertiary") }}

This breaks {{ partial("/home/project/common/layouts/master/includes/leaderboard/tertiary") }}

All the paths seem to be restricted to only be able to respond to relative paths.

When using common views this seems to be a complete nightmare as sometimes you may be trying to call the same files from various locations, in which causes the relative urls to break.

in most cases you end up duplicating views with the changes made to the paths.

For a supposedly scalable framework this seems very silly to add such restrictions. Whos crazy design was this?

Developers need the possibility to use Absolute and relative paths as they desire. I hate when people create frameworks yet strip out the use of basic things which people need.

whats the point of it being a framework if you remove basic common concepts? maybe it should be called a lamework!!

does anbody know how to fix this, or are there any hacks for this this is very frustrating. i dont want to make duplicate views / layouts in order to repair this issue.

I need a way to use absolute paths. Relative paths are not acceptable in my circumstances

Thanks Daniel

Please do not suggest work arounds using relative paths. This question is simple i need absolute paths working nothing else.

if you have 10x folders deep in your controllers and a single common view embeded as a partial then you need to rewrite the relative paths 10x to suit each level of the controller subfolders. With absolute paths you have only a single path required and a single change when updating it, as you can use variables.

a project with 10x controller subfolders is not suitable for relative only paths, this is definetly a problem for me

one change in folder level breaks all relative paths, my only current solution is to make a duplicate view for each folder level



43.9k

Here is my system. I'm showing this because perhaps you have not considered making your application multi-module and are "shoehorning" a level of abstract into the controller/action system that can be more easily done another way.

Check out Webird. Here is my Web module and the base module.

I set the view function in each module:

$di->setShared('view', self::getViewFunc($di));

In the base module:

    public static function getViewsDir()
    {
        return self::classNameToDir(get_called_class()) . 'views/';
    }
    public static function getViewFunc($di)
    {
        $viewsDir = self::getViewsDir();
        $viewFunc = function() use ($di, $viewsDir) {
            $view = new View();
            $view->setDI($di);
            $view->registerEngines([
                '.volt' => 'voltService'
            ]);
            $view->setViewsDir($viewsDir);
            $view->setPartialsDir('../../../common/views/partials/');
            $view->setLayoutsDir('../../../common/views/layouts/');
            return $view;
        };
        return $viewFunc;
    }
    public static function classNameToDir($moduleClass)
    {
        $classParts = explode('\\', $moduleClass);
        $moduleName = lcfirst($classParts[1]);
        $moduleDir = self::moduleNameToDir($moduleName);
        return $moduleDir;
    }
edited Apr '15

Hi Yes i am currently using a modular setup similar to yours.

$di->set('view', function() { $view = new View(); $view->setViewsDir(realpath( DIR . '/views/' )); $view->setLayoutsDir('../../common/layouts/'); $view->setTemplateAfter('master/index');

However i notice you have the $view->setPartialsDir() written inside the module whereas i have been writing the partials paths within the views by using this may offer me a better solution, i would still prefer to be able to use absolute paths for edges cases however for my current usage by using the setPartialsDr() method maybe sufficent.

I would still request absolute paths be added / available for developers though i was almost considering using twig instead to replace volt. However i will try this and see how far i get.

Thanks for your help Daniel



43.9k

I was a bit confused as to the state of Webird and I have an improved solution from my proprietary code. I'll add it to Webird when I have time.

base Module.php

    public static function getViewFunc($di)
    {
        $viewsDir = self::getViewsDir();
        $viewFunc = function() use ($di, $viewsDir) {
            $view = new View();
            $view->setDI($di);
            $view->setViewsDir($viewsDir);
            $view->setLayoutsDir('_layouts/');
            $view->setPartialsDir('_partials/');

            $view->registerEngines([
                '.volt' => 'voltService'
            ]);

            return $view;
        };

        return $viewFunc;
    }

Add a common function to Volt to allow to use of common partials to all modules

$compiler->addFunction('common', function($partial) {
    return '$this->partial(\'../../../../common/views/partials/\' . ' . $partial . ')';
});


43.9k

Well there are two approaches there.



43.9k

Also I agree that Volt can be a huge pain in the ass to setup and there are all sorts of rough edges. It works good once you fit it to your needs though.



6.9k

I've created something like that

In controller

$template = $this->template->getString('user_experiences/ang-templates/experiences_form.volt');

$data = array(
    'id' => $ue->getId(),
    'template' => $template,
    'experience' => $experience
);
$this->response->setStatusCode(200, 'OK');
$this->response->setJsonContent($data, JSON_FORCE_OBJECT);
$this->response->send();

in services

$di->set('template', function() use ($config) {
    return new APP\Extra\Template($config->application->cacheDir, $config->application->viewsDir);
});
<?php
namespace APP\Extra;


use Phalcon\Mvc\View\Engine\Volt\Compiler;

class Template
{
    var $compiledPath;
    var $templatesDir;
    var $compiler;

    function __construct($compiledPath, $templatesDir)
    {
        $this->compiledPath = $compiledPath;
        $this->templatesDir = $templatesDir;

        $this->compiler = new Compiler();

        $this->compiler->setOptions(array(
            "compiledPath" => $this->compiledPath,
            'compiledSeparator' => '_',
            'stat' => true,
            'compileAlways' => true
        ));
    }

    public function getString($templatePath, $data = null)
    {
        if (!empty($data)) {
            extract($data);
        }
        $this->compiler->compile($this->templatesDir . $templatePath);

        ob_start();

        include $this->compiler->getCompiledTemplatePath();

        return ob_get_clean();
    }
}