views:

41

answers:

1

I am using a custom Router to enable pages like:

mytutorialsite.com/category/:categoryname

# added to application.ini
resources.router.routes.categorynameOnCategory.route = /category/:categoryname
resources.router.routes.categorynameOnCategory.defaults.module = default
resources.router.routes.categorynameOnCategory.defaults.controller = category
resources.router.routes.categorynameOnCategory.defaults.action = categoryname

I also have database table 'categories' in which all categories are stored. For example, let's say the following categories are currently stored in my database:

- html
- css
- js
- php

This means, the following pages exist:

  • mytutorialsite.com/category/html
  • mytutorialsite.com/category/css
  • mytutorialsite.com/category/js
  • mytutorialsite.com/category/php

But when you visit a page with a categoryname that is not listed in the database, like:

  • mytutorialsite.com/category/foo

You should get a 404 Page Does Not Exist message.

How do I achieve that?

+1  A: 

I think you mean with categoryname as action in your route the :categoryname should be used as an action? There are two methods you can use. First is you add only the routes to the router where categories exist. When category/foo is requested the router won't recognize the route and throw the 404 error.

The second option is you catch all category/* routes and inside your action you check if the category exists.

For the first option, add a frontController plugin with a routeStartup function. In this hook you can do:

public function routeStartup(Zend_Controller_Request_Abstract $request)
{
    // Get the router
    $router     = Zend_Controller_Front::getInstance()->getRouter();

    // Fetch all your categories
    $category   = new Application_Model_Category;
    $categories = $category->fetchAll();

    // Loop and add all individual categories as routes
    foreach ($categories as $category) {
        $route  = 'category/:' . $category->name;
        $params = array(
            'module'     => 'default',
            'controller' => 'category',
            'action'     => $category->name
        );

        $route = new Zend_Controller_Router_Route($route, $params);
        $router->addRoute($category->name, $route);
    }
}

The other method is more simple for the route. In your application.ini:

resources.router.routes.category.route      = "category/:action"
resources.router.routes.category.module     = "default"
resources.router.routes.category.controller = "category"

Now all requests from category/SOMETHING will go to the default module, category controller. The dispatcher checks if the action SOMETHING exists. When it does, it executes the action. When not, a Zend_Controller_Action_Exception ("action does not exist") is throw.

So in short, both methods work. With the first you get more control. The second is more simple but when e.g. an editAction, addAction or removeAction in the categoryController exist, they can be triggered as well (so be careful with that method).

PS. Of course, the routeStartup function should have a caching mechanism to prevent a database query on each request.

Jurian Sluiman
Thank you, this was very helpfull!!
Enrico Pallazzo
There's only one problem with the frontcontroller plugin. Now every $category->name has it's own action in the controller. If you want all categorynames to use the same categorynameAction, simply changing 'action' => 'categoryname' doesn't work.
Enrico Pallazzo
That is correct. If you want to route the url to all the same action, it is even more simple (see my assumption at top of my answer). The route is simple: "category/:category" and add an action to that route ("categoryName"). Then in the categorynameAction the parameter "category" is available through $this->_getParam("category").
Jurian Sluiman