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

Priority routing matching links

Hi, tell me, please, what to do when the links are the same, and I want to assign priority to routing?

e.g.

<?php 

...
$router->add('/{slug:.*}', 'Pages::show')->setName('pages-show');
$router->add('/{slug:.*}', 'Categories::show')->setName('categories-show');
$router->add('/{slug:.*}', 'Brands::show')->setName('brands-show');
...

If the page is not found, then the category search, if the category is not found then the brand search. now i did so

<?php 

 //Controller Brands
...
  public function showAction($slug) {

    $page = Pages::findBySlug($slug);

    if ($page) {
        return $this->showPage($page);
    }

     $category = Categories::findBySlug($slug);

    if ($category) {           
        return $this->showCategory($category);
    }

    $brand = Brands::findBySlug($slug);
    if ( $brand) {       
        return $this->showBrand($brand);
    }

    if  ( ! $brand) {
        return $this->error404();
    }

  }
...

but I want to do it somehow at the step of the routes

edited May '18

What's the problem in using it normal way - e.g. dedicated routes per controller/action?



43.9k

Hi,

I understand what you want to achieve, it's an interesting use case I would create a unique Default controller:


// router
$router->add('/{slug:.*}', 'Default::show')->setName('show');

// Default Controller
  public function showAction($slug) {

    $page = Pages::findBySlug($slug);

    if ($page) {
        return $this->showPage($page);
    }

     $category = Categories::findBySlug($slug);

    if ($category) {           
        return $this->showCategory($category);
    }

    $brand = Brands::findBySlug($slug);
    if ( $brand) {       
        return $this->showBrand($brand);
    }

    if  ( ! $brand) {
        return $this->error404();
    }

  }  public function showAction($slug) {

    $page = Pages::findBySlug($slug);

    if ($page) {
        return $this->showPage($page);
    }

     $category = Categories::findBySlug($slug);

    if ($category) {           
        return $this->showCategory($category);
    }

    $brand = Brands::findBySlug($slug);
    if ( $brand) {       
        return $this->showBrand($brand);
    }

    if  ( ! $brand) {
        return $this->error404();
    }

  }

It looks better to me than rewrite 3 times the showAction() in each controller and having 3 times the same route.

edited May '18

I'm pretty sure you can't do this in a route. A route needs to be unique. Plus, the router doesn't have the logic for trying to retrieve a model to see if records are found.

I'd have 4 routes. 1 for each type of model, and 1 generic route:

$router->add('/{slug:.*}', 'Generic::show')->setName('show');
$router->add('/pages/{slug:.*}', 'Pages::show')->setName('pages-show');
$router->add('/categories/{slug:.*}', 'Categories::show')->setName('categories-show');
$router->add('/brands/{slug:.*}', 'Brands::show')->setName('brands-show');

I'd have 1 route that points to a single controller. Then in that controller logic probably the cleanest solution would be to do a query to see if a Page is found - if it is forward() or redirect the request to the Page controller. If no Page is found, move on to check for a Category, etc.

edited May '18

Thanks for the answer. I just had it done from the beginning :)

I had a RouteController, which was an intermediate action. Next to the router were the comments of controllers that fell under his actions:

<?php 

/**
*
* Pages::show
* Categories::show
* Brands::show
*/
$router->add('/{slug:.*}', 'Route::show')->setName('route-show');

/**
*
* Categories::subcategoryFilter
* Categories::brandFilter
* Products::show
*/
$router->add('/{slug:.*}/{sub_slug:.*}', 'Route::subShow')->setName('route-sub-show');
...

And these are just two examples of matching routs. I would not want the confusion. I need clear structure of the routs, as I wrote above:

<?php 

...
$router->add('/{slug:.*}', 'Pages::show')->setName('pages-show');
$router->add('/{slug:.*}', 'Categories::show')->setName('categories-show');
$router->add('/{slug:.*}', 'Brands::show')->setName('brands-show');
...

But I would like to be able to have an opportunity inside the Action after checking for the presence of the model, for example Brands::findBySlug($slug) is no found, do something type $this->router->noMatches(). And the router will go to the next priority route

$router->add('/{slug:.*}', 'Categories::show')->setName('categories-show');

Well these are of course wishes, in reality, probably, I can only do with the help of RouteController

Hi,

I understand what you want to achieve, it's an interesting use case I would create a unique Default controller:


// router
$router->add('/{slug:.*}', 'Default::show')->setName('show');

// Default Controller
 public function showAction($slug) {
...
 }

It looks better to me than rewrite 3 times the showAction() in each controller and having 3 times the same route.

No, no, this routing structure is too redundant :)

I'm pretty sure you can't do this in a route. A route needs to be unique. Plus, the router doesn't have the logic for trying to retrieve a model to see if records are found.

I'd have 4 routes. 1 for each type of model, and 1 generic route:

$router->add('/{slug:.*}', 'Generic::show')->setName('show');
$router->add('/pages/{slug:.*}', 'Pages::show')->setName('pages-show');
$router->add('/categories/{slug:.*}', 'Categories::show')->setName('categories-show');
$router->add('/brands/{slug:.*}', 'Brands::show')->setName('brands-show');

I'd have 1 route that points to a single controller. Then in that controller logic probably the cleanest solution would be to do a query to see if a Page is found - if it is forward() or redirect the request to the Page controller. If no Page is found, move on to check for a Category, etc.