Cms: Feature Request: Give sections an option to route to a controller not just a template

Created on 18 Feb 2018  ·  10Comments  ·  Source: craftcms/cms

With Craft 3 we can have a custom module for site specific features, controllers, services, twig extensions, you name it. And it's AAAAAMAZING. However, one thing that's bugging me is this: I've worked on (and am working on currently) sites where every page needs to run through custom controllers to make sure custom variables are set, custom logic is run etc. I've jumped through elaborate hoops to make this work in Craft 2. But in Craft 3, it seems to me there's an opportunity to allow routing to a custom Yii controller as an option and not just a template. If we could specify the controller and method a section should run for the entry's URL in the same way we can specify a Yii controller in a route (for instance dev/locations/entry in the case of a site I'm working on right now, that would be super duper fantastic.

So basically, as a feature request, anywhere we can tell Craft in the CMS to route a URI to a template, also give us the option to route to a controller action.

enhancement system administration

Most helpful comment

I’ve thought about this, but unsure whether enough people would want it, to be worth the added UI complexity.

You can take over elements’ routing though, using the EVENT_SET_ROUTE event.

use craft\base\Element;
use craft\events\SetElementRouteEvent;
use yii\base\Event;

Event::on(Element::class, Element::EVENT_SET_ROUTE, function(SetElementRouteEvent $e) {
    /** @var Element $element */
    $element = $e->sender;

    $params = [
        'element' => $element,
    ];
    $e->route = ['dev/locations/entry', $params];
});

All 10 comments

Meant to say also that the entry that's normally pre-loaded as a variable available in Twig could be an incoming route parameter or attached to the route object in some way.

I’ve thought about this, but unsure whether enough people would want it, to be worth the added UI complexity.

You can take over elements’ routing though, using the EVENT_SET_ROUTE event.

use craft\base\Element;
use craft\events\SetElementRouteEvent;
use yii\base\Event;

Event::on(Element::class, Element::EVENT_SET_ROUTE, function(SetElementRouteEvent $e) {
    /** @var Element $element */
    $element = $e->sender;

    $params = [
        'element' => $element,
    ];
    $e->route = ['dev/locations/entry', $params];
});

Very helpful, thanks! The only additional argument I'll make in favor of the feature request is perhaps maybe having the route start with a keyword Craft can look for, no additional UI needed. Maybe something like actionRoute/dev/locations/entry. Otherwise, manually doing something like this with that event is probably fine.

Not a bad idea!

Played around with it. Issue with supporting the template path being set with something action: is, the column is _called_ “Template”. We’r really need to rename it to “Route” if we support anything besides template paths. And if we rename it to “Route”, it would be pretty awkward that routes defined here default to template paths and you need to specify action: if you want it to go to a controller action; but routes defined in config/routes.php default to controller actions, and if you want it to go to a template, you have to specify that with ['template' => 'template/path']. So I think when we add support for action paths here, we just need both types of routes to explicitly define what they are.

Probably something like this:

screen shot 2018-02-19 at 4 02 03 pm

Don't forget about #1489 when thinking about updates to routes. 😉

Good point @carlcs.

@brandonkelly given your piece of code:
$e->route = ['dev/locations/entry', $params];
Where would $params end up?

I routed it onto a module controller, but the params aren't being set as controller action arguments.

Nevermind that @brandonkelly.

UrlManager will do the trick:
Craft::$app->getUrlManager()->getRouteParams();

@gijsstegehuis Any parameters that match the names of your controller action arguments will be passed to those. So you could do this:

public function actionEntry(\craft\base\ElementInterface $element)
{
    // $element will be whatever $params['element'] was in the route
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

darylknight picture darylknight  ·  3Comments

michaelhue picture michaelhue  ·  3Comments

bitboxfw picture bitboxfw  ·  3Comments

timkelty picture timkelty  ·  3Comments

angrybrad picture angrybrad  ·  3Comments