简体   繁体   中英

Zend Framework 2 Routing Segment Error

I tried to understand ZF2 Module Routing, but I have a problem. I would like to list products by period and generate a link for each of the periods (today, this-week, this-month, all). For example:

<a href="<?php echo $this->url('Application', array('action' => 'index', 'period' => 'this-week')); ?>">This week</a>

output: localhost/application/this-week/

When I click on this link, appears this error:

A 404 error occurred
Page not found.
The requested controller was unable to dispatch the request.

this is my module.config:

 .....................
       'router' => array(
             'routes' => array(
                 'Application' => array(
                     'type'    => 'Segment',
                     'options' => array(
                         'route'    => '/application/[:action/][:period/]',
                         'constraints' => array(
                             'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
                             'period' => '(today|this-week|this-month|all)'
                         ),
                         'defaults' => array(
                             'controller' => 'Application\Controller\ApplicationController',
                             'action' => 'index',
                             'period' => 'all'
                         ),
                     ),
                 ),
             ),
         ), ...........................

Where am I doing wrong? I tried to change:

 'period' => '(today|this-week|this-month|all)'

to

'period' => '[a-zA-Z][a-zA-Z0-9_-]*'

but it doesn't work again.

inside my controller, index action is empty actually:

public function indexAction(){

}

index.phtml contains only a echo link:

<a href="<?php echo $this->url('Application', array('action' => 'index', 'period' => 'this-week')); ?>">This week</a>

NEW EDIT

I've decided to using query string for my use. It's more simple to implement, it isn't elegant but is moooore simple :D ...I thought like so, with a switch for "higher rigidity":

public function indexAction(){
   ...getQuery method ...

   switch($period){
       case'today':
       .......
       break;
        case'this-week':
       .......
       break;
        case'this-month':
       .......
       break;
       default:
       // if query string is null or contains other characters, sets default   case "all"
       ... 
       break;
   } 
}

url function:

<a href="<?php echo $this->url('Application', array('action' => 'index'), array('query' => array('period' => 'this-week'); ?>">This week</a>

output:

localhost/adopted/?period=this-week

inside module.config:

   .....................
           'router' => array(
                 'routes' => array(
                     'Application' => array(
                         'type'    => 'Segment',
                         'options' => array(
                             'route'    => '/application/[:action/]',
                             'constraints' => array(
                                 'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
                             ),
                             'defaults' => array(
                                 'controller' => 'Application\Controller\ApplicationController',
                                 'action' => 'index',
                             ),
                         ),
                     ),
                 ),
             ), ...........................

Hello you have did bracket left and right here (today|this-week|this-month|all) . if you remove this bracket your route will work. and one more thing 'Application\\Controller\\ApplicationController', here you need to write 'Application\\Controller\\Application'

.....................
   'router' => array(
         'routes' => array(
             'Application' => array(
                 'type'    => 'Segment',
                 'options' => array(
                     'route'    => '/application/[:action/][:period/]',
                     'constraints' => array(
                         'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
                         'period' => 'today|this-week|this-month|all'
                     ),
                     'defaults' => array(
                         'controller' => 'Application\Controller\Application',
                         'action' => 'index',
                         'period' => 'all'
                     ),
                 ),
             ),
         ),
     ), ...........................

With a path like /application/this-week/ , ZF has no way of knowing whether this-week is an action or period, since both are optional and the string matches the constraints for both. To fix this you need to remove this ambiguity. You have a few options:

Option 1: Add some constraints for action , so that it will only match valid actions, something like:

'constraints' => array(
    'action' => '(index|foo|bar)',
    'period' => '(today|this-week|this-month|all)'
),

Option 2: Make either action or period required, by removing the square brackets from them in your routing config. (If you make index required you will end up with 'index' in your URLs.)

Option 3: Add a separate route for this URL which doesn't include the action in the path (since you don't want it there), but has some other way of distinguishing it from the application route:

'router' => array(
     'routes' => array(
         'Application' => array(
             'type'    => 'Segment',
             'options' => array(
                 'route'    => '/application/[:action/]',
                 'constraints' => array(
                     'action' => '[a-zA-Z][a-zA-Z0-9_-]*''
                 ),
                 'defaults' => array(
                     'controller' => 'Application\Controller\ApplicationController',
                     'action' => 'index'
                 ),
             ),
         ),
         'period' => array(
             'type'    => 'Segment',
             'options' => array(
                 'route'    => '/application/period/[:period/]',
                 'constraints' => array(
                     'period' => '(today|this-week|this-month|all)'
                 ),
                 'defaults' => array(
                     'controller' => 'Application\Controller\ApplicationController',
                     'action' => 'index',
                     'period' => 'all'
                 ),
             ),
         ),
     ),
 ), 

You'd also change the URL helper call:

<a href="<?php echo $this->url('period', array('period' => 'this-week')); ?>">This week</a>

This would give you a URL like /application/period/this-week/ .

Your thinking overall is fine, you just want to tweak your route a bit. I'd recommend a few things:

  • Don't call your route Application, give it a meaningful name. Seems like a catch all with a duration?
  • Remember that routes in ZF2 are LIFO, so stick this one near the top so that more meaningful routes can interrupt it

With these little things in mind, this route works:

'catchall_with_period' => array(
     'type'    => 'Segment',
     'options' => array(
         'route'    => '/application[/:action[/][:period[/]]]',
         'constraints' => array(
             'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
             'period' => '(today|this-week|this-month|all)'
         ),
         'defaults' => array(
             'controller' => 'Application\Controller\ApplicationController',
             'action' => 'test',
             'period' => 'all'
         ),
     ),
 ),

I tested locally, and it has the intended effect.

In my personal experience, these are the kind of routes that have you scratching your head 2 years from now hehe. Why is this doing this? Catch-all routes, beware!

Most probably your controller config is wrong:

'defaults' => array(
    // 'controller' => 'controller service name'
    'controller' => 'Application\Controller\ApplicationController',
    'action' => 'index',
    'period' => 'all'
),

ZF2 will kindly ask the Controller Manager for a service named Application\\Controller\\ApplicationController . If no such service (controller) is registered under that name, error "Cannot dispatch" will be thrown.

Usually controllers in the Controller Manager are configured through Module's config that way:

'controllers' => array(
    'invokables' => array(
        // service name => service FQCN
        'Application\Controller\Application' => 'Application\Controller\ApplicationController'
    )
)

To sum up, your route should look that way I believe:

'defaults' => array(
    'controller' => 'Application\Controller\Application',
    'action' => 'index',
    'period' => 'all'
),

I can be wrong of course because you did not provide the configuration of your controllers.

For future reference please read more about default Service Managers configured in the framework , how to configure them, what are invokables, factories, etc.

By the way,

'constraints' => array(
    'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
    'period' => '(today|this-week|this-month|all)'
),

the regexp for period is invalid as well, because it would accept phrases like xxxtodayyyy , grall , tttthis-monthhhh , so change '(today|this-week|this-month|all)' pattern to '^(today|this-week|this-month|all)$'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM