0

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',
                             ),
                         ),
                     ),
                 ),
             ), ...........................

4 Answers4

1

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'
                     ),
                 ),
             ),
         ),
     ), ...........................
Dharmesh Vasani
  • 475
  • 2
  • 4
  • 19
0

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/.

Tim Fountain
  • 33,093
  • 5
  • 41
  • 69
  • Not sure on your reason here as there is already a default for `action` (providing the request is `application/index/this-week`). I think it's the controller name, `Application\Controller\ApplicationController` that should be `Application\Controller\Application`. – AlexP Jun 25 '15 at 16:27
  • Thanks tim for your solution, I've decided to use query string, is more simple and it doesn't make headache :D. Look the first post. What do you think about the new solution? – Alessandro Corradini Jun 25 '15 at 20:34
0

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!

Saeven
  • 2,280
  • 1
  • 20
  • 33
  • 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; } } ` – Alessandro Corradini Jun 25 '15 at 20:18
  • I'm sorry but I dont understood how to improve the formatting inside a comment O_O – Alessandro Corradini Jun 25 '15 at 20:20
  • Fair enough, but it's bad form to post a question, have a bunch of folks answer, and then change your question to something radically different. – Saeven Jun 26 '15 at 03:32
0

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)$'

Mike Doe
  • 16,349
  • 11
  • 65
  • 88