phpphalcon

why using viewSimple renderer in Phalcon corrupts main renderer


First I declare simple view like this:

$di->set('viewSimple', function() {
    $view = new \Phalcon\Mvc\View\Simple();
    $view->setViewsDir('../app/views/');
    $view->registerEngines(array(
        ".volt" => 'volt'
    ));
    return $view;
});

then to generate html email, I use it as following:

public function renderHTMLEmail($template_name, $template_params) {
    $content = $this->viewSimple->render("emails/$template_name", $template_params);
    return $this->viewSimple->render("emails/master", array( 'content' => $content) );
}

My emails are being generated just fine, but whenever I call my renderHTMLEmail function actual page rendering is somehow corrupted and page appears totally blank (I have to use redirect as workaround). This is a mystery to me as main view renderer is completely different object. Can I prevent this?

Or does anybody have recommended method of generating arbitrary pieces of html outside of main view rendering process which would not interfere with it? There is couple of similar questions on SO, but none of solutions work. They either don't generate my email or they corrupt main view.


Solution

  • Found a solution, when registering the "\Phalcon\Mvc\View\Simple" component into the DI container make sure to use a new volt instance otherwise it will join up with the application's \Phalcon\Mvc\View volt instance somehow. This is what lot (https://stackoverflow.com/users/1672165/lot) was suggesting in the comments.

    Code sample:

    public function getTemplate($name, $params)
    {
        $parameters = array_merge(array(
            'publicUrl' => $this->getDI()->getApp()->url->host . $this->getDI()->getApp()->url->baseUri
        ), $params);
    
        $app = $this->getDI()->getApp();
    
        $this->getDI()->set('simpleView', function() use ($app) {
            $view = new \Phalcon\Mvc\View\Simple();
            $view->setViewsDir(APP_DIR . $app->application->viewsDir);
            $view->registerEngines(array(
                ".volt" => function ($view, $di) {
                    $volt = new \Phalcon\Mvc\View\Engine\Volt($view, $di);
                    $volt->setOptions(array(
                        'compiledPath'      => APP_DIR . '/cache/volt/',
                        'compiledSeparator' => '_',
                        'compiledExtension' => '.compiled'
                    ));
                    $compiler = $volt->getCompiler();
                    $compiler->addFunction('is_a', 'is_a');
                    return $volt;
                }
            ));
            return $view;
        });
    
    
    
        /* @var $simpleView \Phalcon\Mvc\View\Simple */
        $simpleView = $this->getDI()->get('simpleView');
    
        foreach ($parameters as $key => $value) {
            $simpleView->{$key} = $value;
        }
    
        $html = $simpleView->render('emails/' . $name, $parameters);
    
        return $html;
    }
    

    Sample was pulled straight from our working app so may need some re-working but should help solve the original issue.

    This works for me using \View as the application DI registered view component which renders controller action volt views and the above \View\Simple with fresh volt registration successfully emails and allows the original view with volt to carry on.

    This was asked a while ago however i've not seen a working solution anywhere else.

    For completeness I've registered a github issue with the findings: https://github.com/phalcon/cphalcon/issues/3096