Solved thread

This post is marked as solved. If you think the information contained on this thread must be part of the official documentation, please contribute submitting a pull request to its repository.

Do I have to place the same main view in multiple places when using a sub-controller?

I am using a sub-controller structure.


In the above sample, the view directory is changed in app/constrollers/admin/ControllerBase.php as follows.

class ControllerBase extends Controller

    public function afterExecuteRoute()
        $this->view->setViewsDir($this->view->getViewsDir() . 'admin/');

However, with this method, I think it is necessary to have main-view( the overall layout as HTML ), partials, and layouts in each views directory. Because it was written in the document as follows.

public setMainView (mixed $viewPath)
Sets default view name. Must be a file without extension in the views directory

I think this is too inefficient, but isn't it common? (By the way, I want to use multiple sub-contollers.)

It may be possible to solve by changing the names of all the controllers, but it seems that it is not a good management to arrange all the different functions in the same hierarchy, and at least the top controller of the divided controller is I think index is appropriate.

edited Sep '19

You don't have to. The choice of the developer in this case makes sense since he wants a specific view in the admin pages. If you check the ControllerBase.php one level higher, you'll find that there is no afterExecuteRoute() method declared. You can also pick any view from your sub-controllers as well, or just let them flow automatically to their own view.

Thank you for your reply.

You can also pick any view from your sub-controllers as well, or just let them flow automatically to their own view.

How can I do that? ( especially “automatically” ) I am thinking about the following structure. (Of course change is possible)

        index/     (for IndexController)
        search/     (for SearchController)
            index/     (for admin/IndexController)
            users/     (for admin/UsersController)
            index.volt     (for IndexController)
            search.volt     (for SearchController)
                index.volt     (for admin/IndexController)
                users.volt     (for admin/UsersController)
            menu.volt     (for both)
        html5.volt     (for both)

It seems that Phalcon cannot find admin/index.volt unless the controller under admin is explicitly specified with setViewsDir().

And if you set it with setViewsDir(), it will not find html5.volt.

This is correct because the default mainView (= html5.volt) is not under the view/admin.

I haven't tried layouts and partials yet, but I really want to use them.

edited Sep '19

That's the default behaviour. I like to pick a view to display an error message in case needed, i.e:

class ControllerBase extends Controller
    public function beforeExecuteRoute()
        if (! $this->user->isAuthenticated()) {
            $this->view->setvar("Msg", "Your session has expired. Please login again.");
            return false;

And in index/error just print Msg. If the user is authenticated, the views flow will continue as usual. And, of course, within the indexController, you can keep picking other views, if there is an error pick the error page and send the appropriate message or just let it display its own view. The Views doc explains the flow very well, you might find more possibilities for your project.

This example is similar to the one that started your question: this function is ideal for admin sub-controller. For the other ones, you can pick views based on other rules. Ideally, to take advantage of the automated flow of Phalcon, keep in mind that views mirror the controllers (it's MVC after all).

I want to forward to the login page instead of displaying an error page when an authentication error occurs, but Controller:beforeExecuteRoute() did not work. Probably because I don't understand how to use beforeExecuteRoute(), but attaching the authentication check to the dispatch:beforeExecuteRoute event worked well, so I decided to use it.

And I thought your suggestion to use pick() was good, so I wrote in controller:initialize(), create a path for action view from controller namespace and action name, and pass to pick().

It was very helpful. Thank you very much.

Glad that it helped. In Routing doc you'll find more info about beforeExecuteRoute. It's strongest point, as in the example that started your question, is that it covers all the controllers extended from it, so you don't have to add the authentication request in each one of them.

It is a little difficult to understand events and dispatch loops, but it is powerful and useful. However, my usage this time also overrides the default behavior with the same value, so I think there should be a smarter way.

If possible, I would like router to automatically determine subdirectories from the relation between the controller's namespace and directory registered with Phalcon\Loader::registerNamespaces() and REQUEST_URI. And it should be reflected when deciding the directory to search for view and controller-layout, tag-helper link and form generation.

That's exactly how controllers and actions work in Phalcon. If I understand you well, you might not need too many sub-controllers, but a good grouping in your router. Follow this guide, it will save you time :

Does your suggestion of "grouping" mean dividing into modules? I tried a little, but since the mutual cooperation is deep in this project, I adopted sub-controller.

Actually, I was expecting the previous "automatically determine subdirectory ...", but it was a pity that it was not implemented.

With the router in Phalcon the sky is the limit. Take this example :

        'controller' => 1,
        'action'     => 2,
        'params'     => 3,

You can go as deep as you want. By grouping I refer to use multiple actions in a controller rather than spreading them in sub-controllers. And if many devs are involved, it might be of help the multi-module approach, makes it easier to delegate tasks. The example is taken from the routing doc, you'll find many more possibilities in it.

I'm using sub-controllers in my latest project.

For every sub-controller namespace, I have a new Base controller. Base::afterExecuteRoute() I re-define with $this->view->setViewsDir(). The partials directory stays the same, but the base view directory changes.

Also, if your question has been answered, can you click the "Accept Answer" button on the answering reply? Then others can know the problem has been solved.

I'm sorry, I was late.

To dipropito. I don't like having many controllers in the same hierarchy without being classified, so I'm sorry, but I don't use the proposed method. For that reason, I think there is no way to register multiple namespaces. I'm very happy if the directory is resolved according to PSR with just the basic namespace and directory registration, and I hope Phalcon will do so. I am grateful for your suggestion.

To Anderson. I think my management will fail, so I want to avoid it, creating multiple files with almost the same content. If I use BaeController, which inherited from CommonBaseController, I might be able to avoid failure, but I think it will be more complicated and increase the number of files. So I would like to configure multiple sub-controllers with as few (one is optimal) files as possible. Thank you.