0
votes

I have a question about using volt-template engine in user components and with simple view.

I wrote a class for user component (extended it form Phalcon\Mvc\User\Component). It has a method to render a simple view:

public function renderPath()
{
    $view = $this->getDi()->getView();

    $simpleView = new \Phalcon\Mvc\View\Simple;
    $simpleView->setViewsDir($view->getViewsDir().'components/');

    $render = $simpleView->render($this->key.'/path');

    return $render;
}

So, I fetch a current view component to get it's viewsDir and use it as a path for simple view.

This initialization works fine but offers only rendering phtml-files whereas I want to be able to render "*.volt".

If I register engine for volt-template ($simpleView->registerEngines(['.volt' => 'volt']);) then I get an Phalcon\Mvc\View\Exception "A dependency injector container is required to obtain the application services".

However, if change view's DI with setDI by running $simpleView->setDi($this->getDi()); I do not get neither the exception still nor output ($render === null). But in a cache directory I can see that the volt-template is compiled.

To register component I use this code:

    $di->set('catalogComponent', function () {
        $component = new \ABLib\Components\CatalogComponent;
        $component->setCatalogProvider();

        return $component;
    }, true);

and to render view: {{ this.catalogComponent.renderPath() }}

So, the question is what I'm doing wrong? How can I use volt-template engine inside my component?

Updated:

Managed to solve this problem. Unfortunately, I have no idea why it works. So, in my app I use code like this:

$simpleView = new \Phalcon\Mvc\View\Simple;
$simpleView->setDI($this->getDI());
$simpleView->registerEngines(array(
    '.volt' => function ($view, $di) {
        $volt = new VoltEngine($view, $di);
        $volt->setOptions(array(
            'compiledPath' => BASE_PATH.'/cache/',
            'prefix' => 'volt_',
        ));

        return $volt;
    }
));

And then call $simpleView->render() to render view. The thing that I can not understand - why it does not work when I add template engine with service. However, when I add a new definition everything starts work.

1
I didn't read all, but I think that last should be: {{ catalogComponent.renderPath() }} (without this) - that is when using standard volt/view setting. - jodator
Yep, that's right. Remove it. - vansanblch

1 Answers

1
votes

I ran into the same issue when trying to attach a volt render engine to a simple view. I got weird results when I tried to reuse the volt instance I had previously registered with my dependency injection services. I think this is because when you instantiate the volt engine, you need to pass in a view. The engine must be tightly coupled with the view to which the volt engine is initially associated. Consequently, you don't get the same results with a Phalcon\Mvc\View\Simple view that you get with a regular Phalcon\Mvc\View view. I overcame this issue by declaring an additional volt service that I intend to only use when rendering simple views. I use my first volt service with standard views and my second volt service with simple views:

// setup 'volt' engine
$di->set('volt', function($view, $di) use ($config) {
    $volt = new \Phalcon\Mvc\View\Engine\Volt($view, $di);
    $volt->setOptions(
        array(
            'compiledPath'      => CACHE_PATH . '/views/',
            'compiledExtension' => '.compiled',
            'compiledSeparator' => '%%',
            'compileAlways'     => true, // performance decrease
            'stat'              => true,
        )
    );
    return $volt;
}, true);

// setup 'simple_volt' engine for simple rendering
$di->set('simple_volt', function($simple_view, $di) use ($config) {
    $volt = new \Phalcon\Mvc\View\Engine\Volt($simple_view, $di);
    $volt->setOptions(
        array(
            'compiledPath'      => CACHE_PATH . '/views/',
            'compiledExtension' => '.compiled',
            'compiledSeparator' => '%%',
            'compileAlways'     => true, // performance decrease
            'stat'              => true,
        )
    );
    return $volt;
}, true);

Though the two services above are identical, the dependency injection of the type of view seems to make a difference in how the rendering engine behaves. When I need to render a simple view and save the output to a variable, I make sure to register it with my simple version of the volt rendering engine:

// create a simple view to help render sections of the page
$simple_view = new \Phalcon\Mvc\View\Simple();
$simple_view->setViewsDir( __DIR__ . '/../views/' );
$simple_view->setDI( $this->di );
$simple_view->registerEngines(array(
    ".volt"  => 'simple_volt'
));

// use the simple view to generate some html
$data_object = $my_data_model->getData();
$data_html = $simple_view->render('index/dataview',array('data_object'=>$data_object));

// pass the rendered simple view as a variable into the regular view
$this->view->setVar('data_html',$data_html);