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

Phalcon\Mvc\View - one view for all actions (no layout for ajax, render layout for non-ajax)

Hello, i extend all my controllers from this one:

abstract class Controller extends Phalcon\Mvc\Controller
{
    /**
     * Disables layout if request is made via ajax
     * @return void
     */
    public function initialize()
    {
        if ($this->request->isAjax()) {
            $this->view->setRenderLevel(Phalcon\Mvc\View::LEVEL_ACTION_VIEW);
        }
    }
}

So, all my actions render layout by default, but if it is ajax request - they do not. It's fine. But i have one controller, where all views are the same (data is very different, but views are really same). I want to use only one template instead of many same files. But, when in my controller i try to pick different view, it does not render a layout. Even if it is not ajax request. I even dropped my initialize() funtion to check. It just renders view without layout:

// Controller::initialize() or Controller::action() context, same result
$this->view->pick('index/index'); // always use index/index.phtml for all actions

Could you please advice the correct way to change view (if it is possible - for all actions in initialize() method in controller in one place), but to make layout appear when controller is handling non-ajax requests?

P.S. Methods names of View component are not self-explaining. Perhaps it is possible to make a little bit more self-explaining names in v 2.0?

E.g. setMainView() would be much more understandable with name setDefaultView(), pick() to setView() etc... It's unbeliveable hard to understand what methods are doing.. But the good framework should provide method names according to users' logical expectations...

Hello, thank you for response,

Hm... this adds some more layout(s) manually, before/after action execution? This solution looks like overengeneering for my issue...

I just need to render my default layout as usually for all controllers/actions, that is set in View object at application runtime. But, instead of using separate view files for action views - i want to setup one, because all actions output same data and now i have same .phtml files.

Is it possible to set action view .phtml file name in one place, without disabling layout and hardcode in every action method?

Example:

    // DI definition
    $di->set('view', function() use ($config) {
        $view = new \Phalcon\Mvc\View();
        $view->setViewsDir('app/views/');
        $view->setLayout('index');
        return $view;
    });
class SearchController extends Phalcon\Mvc\Controller
{
    public function initialize()
    {        
        // don't know how this function is called
        // it should say to phalcon: "Please: stop rendering default views for all actions now. Render only search/results.phtml for everything"
        $this->view->useSpecifiedPhtmlFileForAllActionsNow('search/results');
        // after function is called, default layout "index.phtml" is rendered with view "search/results.phtml" inside
    }

    public function musicAction()
    {
        // only gets data and sets it to view, do not select any .phtml page itself
    }    

    public function videosAction()
    {
        // only gets data and sets it to view, do not select any .phtml page itself
    }    

    public function booksAction()
    {
        // only gets data and sets it to view, do not select any .phtml page itself
    }    
}

Btw, @Phalcon, in code i found that param for method pick() can be an array - and the logic is very different: https://github.com/phalcon/cphalcon/blob/master/ext/mvc/view.c#L1278

Perhaps this way i can select view filename withput disabling my layout?

I found a bug regarding pick method. If i call it using array, not a string, everything works fine:

$this->view->pick(['search/index']); // layout is rendered
$this->view->pick('search/index'); // only action view is rendered

I will create a bug on github, thanks.