We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Render multiple controllers in view

Hi,

I've been trying something for quite a while, but I do not know how to implement this and I can't find any information about it.

I have i.e. three classes:

    class HeaderController extends BaseController {
        public function indexAction() {
            $this->view->title = \Phalcon\Tag::getTitle(); 
            $this->view->pick('common/header');
        }
    }

    class FooterController extends BaseController {
        public function indexAction() {
            $this->view->pick('common/footer');
        }
    }

    class HomeController extends BaseController {
        public function indexAction() {
            \Phalcon\Tag::setTitle('Home');
            $this->view->pick('common/home');
        }
    }

As you can guess I would like to render the header before the home template and the footer after the home template. However if I in example use Phalcon::setTitle I want to get the right value set in the HomeController.

I know I could use {% extends "templates/base.volt" %} provided by Volt, however I do not wish to have variables append to the view to be shared across different controllers.

I've been playing around with setRenderLevel, render, start and finish, however I can't get it to work.

This is my View in the DI so far:

    $di->set('view', function() {
        $view = new View();

        $view->setBasePath(APP_PATH.'view/');
        $view->setViewsDir('');

        $view->setRenderLevel(View::LEVEL_BEFORE_TEMPLATE);
        $view->render('common/header', 'index');

        $view->setRenderLevel(View::LEVEL_AFTER_TEMPLATE);
        $view->render('common/footer', 'index');

        $view->setRenderLevel(View::LEVEL_MAIN_LAYOUT);

        $view->registerEngines([
            ".volt" => function($view, $di) {
                $volt = new \Phalcon\Mvc\View\Engine\Volt($view, $di);
                $volt->setOptions([
                    'compiledPath'  => APP_PATH.'cache/volt/',
                    'compileAlways' => true,
                ]);

                return $volt;
            }
        ]);

        return $view;
    });
edited Feb '16

header and footer are not views for me they're partials, view is a result of an action so the best way to do that is to include the partials inside the layout before and after the getContent() from the currentView then you can access to all the view data and pass them to the partials.

controller :

class HomeController extends BaseController {
    public function indexAction() {
        $this->view->data = ['title'=>'hello'];
    }
}

layout :

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <?=$this->assets->outputJs('js')?>
        <?=$this->assets->outputCss('css')?>
    </head>
    <body>
        <?=$this->partial('/common/header', $data)?>
        <?=$this->getContent()?>
        <?=$this->partial('/common/footer', $data)?>
    </body>
</html>

Then I would have to pass the variables in every controller, or I would have to define the base HTML tags in every template. Doesn't seem like a clean solution. My common/header template includes the html and head tag, so that I don't have to define them in every template.

Say for instance I have many language files loaded for the header, I do not wish that these variable are accessible to any other controller/view, nor do I wish that the HomeController can overwrite variables with the same name. The same with defined view data,

So you can define in your BaseController a beforeExecuteRoute function that define and normalize $this->view->data to set default data to send to header/footer then you can overwrite it in every controller and use it like in my example, don't understand why you think it is not clean ... if you don't want to include header/footer in the layout add a variable to the view to check if its needed or use another layout.

This is kind of a bastardization of MVC. Controllers should only be used to manage the request and send data to the View. It's the View that should be doing the work of determining what the output should be.

Using your example, get rid of your HeaderController and FooterController, unless you're going to be serving up URLs like /myproject/header/someaction - but I doubt that's the case.

You don't need to pick() which template to use, Phalcon/Volt will automaticall look in your views directory, in the 'home' subdirectory, for index.phtml.

In the aforementioned file is where you set the page title. You can then extend a file like base.phtml or use partial() to bring in your common headers and footers.