I am pretty new to zf2. I am trying to build a RESTful API for our contact management system. We are extending the AbstractRestfulController which uses getList(), get(), etc actions.
Everything works as I would expect it to with the exception of one url route. When I go to this url
/contacts
it successfully routes to the getList() method of my ContactsController. However when I go here.
/contacts/1253378/stats
it routes to the get() method of my StatsController. I would expect that url to route to the getList() method, which I would then return a list of stats.
I would expect adding an /idnumber to the end of that url would route to the get() method of my StatsController, which would return one stat with that id.
Basically I am trying to replicate what is laid out in this REST tutorial, under the But how do you deal with relations section.
http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api#restful
I am hoping my routes are not correct in my module.config.php file
'router' => array(
'routes' => array(
'contacts' => array(
'type' => 'segment',
'options' => array(
'route' => '/contacts[/:id]',
'constraints' => array(
'id' => '[0-9]+',
),
'defaults' => array(
'controller' => 'Contacts\Controller\ContactsController',
),
),
),
'stats' => array(
'type' => 'segment',
'options' => array(
'route' => '/contacts/[:id]/stats[/:id]',
'constraints' => array(
'id' => '[0-9]+',
),
'defaults' => array(
'controller' => 'Contacts\Controller\StatsController',
),
),
),
),
),
Any help would be greatly appreciated.
In your case problem is that id parameter conflicts, recommended way is to use specific parameter names, eg:
'router' => array(
'routes' => array(
'contacts' => array(
'type' => 'segment',
'options' => array(
'route' => '/contacts[/:contactId]',
'constraints' => array(
'contactId' => '[0-9]+',
),
'defaults' => array(
'controller' => 'Contacts\Controller\ContactsController',
),
),
'may_terminate' => true,
'child_routes' => array(
'stats' => array(
'type' => 'segment',
'options' => array(
'route' => '/stats[/:statId]',
'constraints' => array(
'statId' => '[0-9]+',
),
'defaults' => array(
'controller' => 'Contacts\Controller\StatsController',
),
),
),
),
),
),
),
Url /contacts/1253378/stats will match contacts/stats route with contactId set to 1253378
To make that change work, you will need to set protected property identifierName in Contacts\Controller\ContactsController to 'contactId' and in Contacts\Controller\StatsController to statId
Now controllers will properly use separate variables for Id and everything should work fine.
Related
What I'm trying to do is generate a URL using the url view helper in Zend Framework 2
The URL that I am trying to generate should be
my-website.com/app/## (where ## is equal to the "ownerID")
What happens when I generate this using the view helper like this:
$this->url('mymodule', array('action'=>'show', 'ownerID'=>'28'));
is it only generates "my-website.com/app", but I am expecting "my-website.com/app/28" based on the routing configuration.
Here is the route information from my module.config.php file
'router' => array(
'routes' => array(
'mymodule' => array(
'type' => 'segment',
'options' => array(
'route' => '/app',
'defaults' => array(
'controller' => 'MyModule\Controller\MyModule',
'action' => 'show',
),
),
// Defines that "/app" can be matched on its own without a child route being matched
'may_terminate' => true,
'child_routes' => array(
'archive' => array(
'type' => 'segment',
'options' => array(
'route' => '/:action[/:ownerID[/:clientID]]',
'defaults' => array(
),
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'ownerID' => '[0-9]+',
'clientID' => '[0-9]+',
)
),
),
'single' => array(
'type' => 'segment',
'options' => array(
'route' => '/:ownerID[/:clientID]',
'defaults' => array(
'action' => 'show',
),
'constraints' => array(
'ownerID' => '[0-9]+',
'clientID' => '[0-9]+',
)
),
),
)
),
)
),
The same behavior occurs when using $this->redirect()->toRoute.
All of the routes work as expected when you type them manually, it is just the generation of the URL that has me stumped.
To more directly answer the question, it doesn't do what you expect because you are only passing the top level route name ("mymodule") to the URL helper. The ownerID is part of a child route.
What you actually want is:
$this->url('mymodule/archive', array('action'=>'show', 'ownerID'=>'28'));
(or possibly mymodule/single, depending on the output you want).
I'm trying to achieve the routing explained in below but having a lot of trouble (the documentation is like a foreign language). Should routing for each module be kept separate in that module's config file?
"route": Module/Controller/Action
"/": Application/Index/index
"/:example": Application/Campaign/index (with param "campaign" = [example])
"/admin": Admin/Admin/index
"/admin/login": Admin/Access/login
"/admin/:controller/:action": Admin/[defined]/[defined]
I've tried to understand and use the skeleton application to do this and everything works up to the "/admin/controller/action" route where the script times out (I'm guessing there's a recursive loop in there somewhere). My route definitions are:
'home' => array(
'type' => 'literal',
'options' => array(
'route' => '/',
'defaults' => array(
'controller' => 'Application\Controller\Index',
'action' => 'index',
),
),
),
'campaign' => array(
'type' => 'segment',
'options' => array(
'route' => '[/:campaign]',
'constraints' => array(
'campaign' => '[a-zA-Z][a-zA-Z0-9_-]*',
),
'defaults' => array(
'controller' => 'Application\Controller\Campaign',
'action' => 'index',
'campaign' => ''
),
),
),
'admin' => array(
'type' => 'segment',
'options' => array(
'route' => '/admin',
'defaults' => array(
'controller' => 'Admin\Controller\Admin',
'action' => 'index',
),
),
'may_terminate' => true,
'child_routes' => array(
'default' => array(
'type' => 'segment',
'options' => array(
'route' => '/[:controller[/:action]]',
'constraints' => array(
'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
),
'defaults' => array(
),
),
),
),
),
1) Yes, you should separate routing config to modules, ZF2 will merge it automatically. So you need to store home and campaign routes in Application/config/module.config.php and admin route in Admin/config/module.config.php
2) I don't see any global mistakes in your config. Two small things:
2.1) You can use literal instead of segment for admin parent route
2.2) If you want to use :controller as a route param, be sure to make shortcut for it via invokables section of config. For example:
'controllers' => array(
'invokables' => array(
'index' => 'Application\Controller\Index'
'admin' => 'Admin\Controller\Admin'
),
),
Now, for example, url /admin/admin/update is connected with Admin\Controller\Admin->updateAction()
3) I think it's not possible to make some recursive loops using only routing config. So check your code in controllers/services
I'm having and issue with the view helper function this->url() that doesn't return and url from a child route and I get a White Screen of the dead. When I put the url manually in the browser the router recognizes the url well.
I have this in my module.config.php:
'news' => array(
'type' => 'Segment',
'options' => array(
'route' => '/news[/:id]',
'constraints' => array(
'id' => '[0-9]+',
),
'defaults' => array(
'controller' => 'Application\Controller\News',
'action' => 'index',
),
),
'may_terminate' => true,
'child_routes' => array(
'allnews' => array(
'type' => 'Segment',
'options' => array(
'route' => '[/:action[/:tab[/:page]]]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'tab' => '[0-9]+',
'page' => '[0-9]+',
),
'defaults' => array(
'controller' => 'Application\Controller\News',
'action' => 'all',
'tab' => 1,
'page' => 1,
),
),
),
),
),
For example:
/news/2
Works correctly and matches the parent route
And:
/news/all/2/5
Works correctly and matches the child route.
But when I use this in the view-helper I get a White Screen of the Dead:
echo($this->url('news/allnews', array('action' => 'all', 'tab' => '1', 'page' => '1')));
My question is: What it's wrong?? I used this method in others views and worked well.
You do not need to use child routes in combination with Router Segments. One Segment should be sufficient!
'news' => array(
'type' => 'Segment',
'options' => array(
'route' => '/news[/:action[/:id][/:tab][/:page]]',
'constraints' => array(
'id' => '[0-9]+',
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'tab' => '[0-9]+',
'page' => '[0-9]+',
),
'defaults' => array(
'controller' => 'Application\Controller\News',
'action' => 'index',
),
),
),
As long as the Defaultcontroller is sufficient you for your needs you also would not need to have it within your params. Once you need more then 1 you prob want to have another constraint defining the controller.
Now you could simply use the url viewhelper in various ways.
if you only need the default action within your default controller you could write it like so.
$this->url('news');
If you need to route to actions with params you could use the viewhelper like so
$this->url('news', array('action' => $action, 'tab' => $tab, 'page' => $page));
Ideally I would use a Router Literal with Router Segments as child routes since bombarding the router segment with tons of constraints gets messy pretty fast.
...
'custom_route' => array(
'type' => 'Literal',
'priority' => 1337,
'options' => array(
'route' => '/custom',
'defaults' => array(
'__NAMESPACE__' => 'Custom\Controller',
'controller' => 'Index',
'action' => 'index',
),
),
'may_terminate' => true,
'child_routes' => array(
'custom_child' => array(
'type' => 'Segment',
'options' => array(
'route' => '/[:controller[/:action]][/:id]',
'constraints' => array(
'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[0-9]+',
),
'defaults' => array(
),
),
),
),
),
...
Pretty sure this won't help but everything does look right in your routing... Have you tried
$this->url('news/allnews', array('action' => 'all', 'tab' => 1, 'page' => 1))
Don't know how the routing stuff handles contraints on digits and providing strings to url view helper.
You probably either need to enable errors or look in the log to find out the actually error
I'm working on a Zend project and I have some issues with the router/routes.
I want the have these URLs:
www.mydomain.tld/contact/person
www.mydomain.tld/contact/person/formsend
www.mydomain.tld/contact/person/id
The third segment in the URL will be a fixed text "formsend" or it will contain an ID, which is a number like '123456789'.
URL 1 and 3 should both execute the indexAction(), URL 2 must execute the sendAction().
Now I have these route's setup to get URL 1 and 2 working:
return array(
'router' => array(
'routes' => array(
'contact' => array(
'type' => 'Segment',
'options' => array(
'route' => '/contact[/][:dns]',
'defaults' => array(
'__NAMESPACE__' => 'project\Controller',
'controller' => 'Contact',
'action' => 'index',
),
),
'may_terminate' => true,
'child_routes' => array(
'send' => array(
'type' => 'Segment',
'options' => array(
'route' => '[/[:action[/]]]',
'defaults' => array(
'action' => 'send'
),
),
),
),
),
I have no idea how I must change my routes so I would be able to have segment_3 inside the indexAction(). What do I need to change?
It sounds to me you only need two routes:
First define /contact/:type/formsend, then /contact/:type[/:id].
You can make them children of a top-level (non-terminating) /contact or /contact/:type route, or not.
I am trying to get some basic routing done in ZF2 but I am running into some problems.
The section that is giving me trouble is this:
'parent-categories' => array(
'type' => 'literal',
'options' => array(
'route' => '/kategorier/',
'defaults' => array(
'controller' => 'categories',
'action' => 'parent-categories',
),
),
'may_terminate' => true,
'child_routes' => array(
'child-categories' => array(
'type' => 'segment',
'options' => array(
'route' => '/kategorier[/:slug][/:parentCategoryid]/',
'constraints' => array(
'parentCategoryid' => '[0-9]+',
),
'defaults' => array(
'controller' => 'categories',
'action' => 'child-categories',
)
),
),
),
),
The original 'parent-categories' route works just fine, no problem. The problem though is the child-categories route isn't doing anything. I have the URL:
/kategorier/test-test-test-test-test/1/
but this is never matched to anything. I get the error:
The requested URL could not be matched by routing.
If I take the child-categories route out of the "child_routes" section, it always catches the request, even if the url is only /kategorier/. Can anyone see what I am doing wrong here?
A child route appends to the parent route. I.e. what you're currently matching is
/kategorier//kategorier[/:slug][/:parentCategoryid]/
Do it like this
'parent-categories' => array(
'type' => 'literal',
'options' => array(
'route' => '/kategorier',
'defaults' => array(
'controller' => 'categories',
'action' => 'parent-categories',
),
),
'may_terminate' => true,
'child_routes' => array(
'child-categories' => array(
'type' => 'segment',
'options' => array(
'route' => '[/:slug][/:parentCategoryid]',
'constraints' => array(
'parentCategoryid' => '[0-9]+',
),
'defaults' => array(
'controller' => 'categories',
'action' => 'child-categories',
)
),
),
),
),
And i guess this should be working out alright. It's a good advice to NOT have trailing slashes, as you'd ideally always want to begin new routes with one for better readability ;)