How to create a custom router in Zend-Framework?

2019-08-18 08:28发布

问题:

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:

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.