I am beginner working with Zend. I have seen may_terminate in module route configuration. I don't understand what it is for. According to ZF2 official docs,
the option “may_terminate” hints to the router that no other
segments will follow it.
Still I don't get the meaning of no other segments will follow it. What is it here? Can anyone please explain it with small example?
The may_terminate option will indicate to the router that 'this' route is able to be matched solely on the value of its route; even when it defines child_routes.
Consider the following example route configuration.
'router' => [
'routes' => [
'home' => [
'type' => 'literal',
'options' => [
'route' => '/home',
],
'may_terminate' => false,
'child_routes' => [
'foo' => [
'type' => 'literal',
'options' => [
'route' => '/foo',
],
],
],
],
],
],
There is some ambiguity in the above configuration, which only occurs with routes that define children. Do we want to allow our users to match on two routes or just one?
We could allow matching on just the /home part; which would mean we have two routes both
/home and /home/foo or we might only want to allow /home/foo.
This is where the may_terminate option is used. If we browsed to /home in our browser, when the routing occurs the router cannot regard the home route as a matchable route as may_terminate = false. In ZF2 terminology the router cannot "terminate" at this route and continues on searching for a match into the child_routes, which will fail and a 404 error will be raised.
So by modifying the value of the may_terminate option in the above example, we can change the routes that can be matched on.
may_terminate = true
home
home/foo
may_terminate = false
home/foo
Related
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
'<controller:\w+>/<id:\d+>/<action:\w+>' => '<controller>/<action>',
'<controller:\w+>/<action:\w+>' => '<controller>/<action>',
],
],
Not it is clear why references of a /controller/name-action/id/1 do work, /controller/1/name-action do not work, and without hyphen everything works, according to documentation of action name-action it is actionNameAction??
public function actionNameAction($id) {
// some code
}
Inline Actions
In advance all thanks.
\w does not include -.
Change pattern to [\w\-]+.
I think you are confused with zend framework and Yii2.In yii2 it is actionActionName.While using it in url's the capitals are changed to lower case with a hyphen preceding them.
For example,
if the controller is Orders
and the action is OrderAnalysis
then the url would be something like orders/order-analysis.
Moreover any id or any other parameter is added only after routing the app to its correct controller action.
Also now coming to your problem I think i found a backdoor to it-
// creates an anchored URL: /index.php?r=post%2Fview&id=100#content --------------------------
echo Url::to(['post/view', 'id' => 100, '#' => 'content']);
I am in the process of setting up my first apigility project and so far it is going well. I'm having some issues with the routing and how to set it up though.
Suppose I have songs, albums and artist (fictitious example for this question only). I want to do a structure like this:
/artists (GET, POST, PUT, PATCH, DELETE)
/albums (GET, POST, PUT, PATCH, DELETE)
/songs (GET, POST, PUT, PATCH, DELETE)
Pretty easy so far. I have filters on those end-points so I can say:
/artists/?style=jazz
/albums/?year=2012
etc...
Now, I also want to include child end-points like this:
/artist/12345/albums (GET) - get all albums for artists with id 12345
/artist/12345/songs (GET) - get all songs for artists with id 12345
/albums/98765/songs (GET) - get all songs for album with id 98765
How do I set this up in a proper way in apigility?
I started by creating a separate service ArtistAlbum, with route /artists/:artist_id/albums and then changing the entity from ArtistAlbumEntity to AlbumEntity (it is basically that) and the collection from ArtistAlbumCollection to AlbumCollection. The route identifier name is set to artist_album_id though, which I will never use. You cannot delete that though.
This ways feels a bit hacky to be honest.
In effect, the above route /artists/:artist_id/albums is actually an alias for /albums/?artist_id=:artist_id. It is a sort of filter.
How do I implement something like this in a proper way?
You can distinguish different types of relationships between your (REST) classes/resources.
association
aggregation
composition
This is nicely explained here on this blogpost but those relationship types are also nicely defined on Wikipedia.
Understanding those types of relationships will help you on how to define (the hierarchy in) your model and it can also help in organizing your urls. I won't go into details here because you can already find a lot of information on relationship types, nested resources and and rest design on stackoverflow. I would only be repeating things. For example here, here, here, here or here but you can surely find more yourself.
Simply search for: "nested resources REST design"
There is not one commonly accepted solution for url design. People often have personal preferences on how to deal with this. Some people (I do not agree) even believe a proper rest model should not use nested (so no hierarchical) urls but a flat structure for all resources.
Consider the following Zend 2 router configuration in module.config.php
<?php
[
'router' => [
'routes' => [
'api.rest' => [
'type' => 'Hostname',
'options' => [
'route' => 'api.site.dev'
],
'may_terminate' => false,
'child_routes' => [
'homeRoute' => [
'type' => 'Literal',
'options' => [
'route' => '/',
'defaults' => [
'controller' => 'Api\\V1\\Rest\\Welcome\\Controller',
]
],
'may_terminate' => true,
'child_routes' => [
'appRoute' => [
'type' => 'Literal',
'options' => [
'route' => 'app',
],
'may_terminate' => false,
'child_routes' => [
'postsRoute' => [
'type' => 'Literal',
'options' => [
'route' => '/posts',
'defaults' => [
'controller' => 'Api\\V1\\Rest\\Post\\Controller',
],
],
]
]
]
],
]
]
],
]
]
];
Then using Apigility, if you want the route name to run Post resource located at api.site.dev/app/posts, just call it with api.rest/homeRoute/appRoute/postsRoute
Eg: Use the URL Plugin like this $this->url('api.rest/homeRoute/appRoute/postsRoute');
Don't know if it works with older versions but actually I use Apigility 1.4.1 and it works like a charm
I've made a REST API with the Yii2 basic template. I've made some changes to the webconfig so I could use links like web/users and web/users/1. It works fine but I couldn't access the web/index anymore. So i've added some more rules to the UrlManager.
'urlManager' => [
'enablePrettyUrl' => true,
'enableStrictParsing' => true,
'showScriptName' => false,
'rules' => [
//basic/web
'<controller:\w+>/<id:\d+>' => '<controller>/view',
'<controller:[\w\-]+>/<action:[\w\-]+>/<id:[\d]+>' => '<controller>/<action>',
'<controller:\w+>/<action:\w+>' => '<controller>/<action>',
//basic/web/users
['class' => 'yii\rest\UrlRule', 'controller' => ['user', 'car']],
//basic/web/countries
//Id is een string, vandaar de tokens
['class' => 'yii\rest\UrlRule', 'controller' => 'country', 'tokens' => ['{id}' => '<id:\\w+>']],
],
],
With the above code I can acces web/index. I could also access web/users to get a list with users. but I can't acces web/users/1. it gives an 404 error.
edit:
'urlManager' => [
'enablePrettyUrl' => true,
'enableStrictParsing' => true,
'showScriptName' => false,
'rules' => [
//basic/web
/*
'<controller:\w+>/<id:\d+>' => '<controller>/view',
'<controller:[\w\-]+>/<action:[\w\-]+>/<id:[\d]+>' => '<controller>/<action>',
'<controller:\w+>/<action:\w+>' => '<controller>/<action>',
*/
//basic/web/users
['class' => 'yii\rest\UrlRule', 'controller' => ['user', 'car', 'site']],
//basic/web/countries
//Id is een string, vandaar de tokens
['class' => 'yii\rest\UrlRule', 'controller' => 'country', 'tokens' => ['{id}' => '<id:\\w+>']],
],
],
I've changed it like this. Now I can acces web/sites because of pluralize.
But if I go to web/sites/about for example, it will give an 404 error again. So it's not the best solution
I think it won't be easy to maintain a REST API and HTML webpages within the same config file. For example cookies and session usually are disabled with REST as recommended by its stateless nature while you may need both to authenticate a user within a classic HTML page.
I would recommend modifying your app structure and having your REST API implemented as an independent module with its own routing configuration and maybe its own Entry Script without missing with the web entry.
A better structure may look like this : (from the tutorial linked below)
+ web
+ config
+ controllers
...
+ api
+ config
+ modules
+ v1
+ controllers
.htaccess
index.php
Then you'll be able to open your HTML files within web/sites/about while retrieving your resources within api/users/1. Each entry may host its own controllers and own models or they may both share #app/models. Check this step by step tutorial to see how to implement it :
Creating a REST API for
Yii2-basic-template
- by Joachim Werner
You may also check api and auth folders in this app where both are independent REST APIs.
i thought i had the routing under control until i found out that i have now clue of how to have the default action url change, that means:
when ever a user enters a url, for example:
http://www.mysite.com/form/myform
the routing will always redirect him to the default action "show" (one of many actions this controller has):
http://www.mysite.com/form/myform/show
but my url remains the same (with the "show" action):
http://www.mysite.com/form/myform
what am i missing here?
'routes' => array(
'form' => array(
'type' => 'segment',
'options' => array(
'route' => '/form[/:form[/:action]]',
'constraints' => array(
'form' => '[a-zA-Z][a-zA-Z0-9_-]*',
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
),
'defaults' => array(
'controller' => 'Form\Controller\Form',
'action' => 'show',
),
),
),
),
thanks!
edited note:
i have noticed (thanks to #codeHeart marks) that i had some mistakes/misclarification trying to explain the problem, so i edited the main question examples.
thanks again all!
Looking at this in your question/
http://www.mysite.com/controller
and your router configuration I expect that should be throwing a 404 error, as there is no matching route in your config that matches /controller(If there are more routes other than the one that you show in you question, let us know or maybe you mistyped this url).
Apart from above,
your route tells to do the following:-
if url is
http://yoursite/form OR
http://yoursite/form/controller
go to the controller action that you have mentioned in the defaults, as the route was matched to the url but didn't get matched completely to an action so going to the default.
A non existing controller or a non existing action should be throwing 404. e.g
http://yoursite/form/controller/non-existing-action
Even this url
http://yoursite/form/
won't get matched according to your route and will be throwing a 404.
And for your question if you want to change the default action to something other then the "show" action, simply change the action parameter/key in defaults
'defaults' => array(
'controller' => 'Form\Controller\Form',
'action' => 'some-other-action',
),
Hope this helps and sorry if I was of no help.
I have a controller that can be invoked as modulename/xmlcoverage with index action and some other actions, let say testAction().
The url to this controller is xml/coverage.
The default way is then that xml/coverage maps to my index action. And that xml/coverage/test maps to testAction. If I need an id for testAction, the url would be like xml/coverage/test/33 for instance.
However, for index action, it would need to be xml/coverage/index/33
Where I would like it to be xml/coverage/33.
This is my route
'xmlcoverage' => array(
'type' => 'segment',
'options' => array(
'route' => '/xml/coverage[/:action][/:id]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[0-9]+',
),
'defaults' => array(
'controller' => 'modulename/xmlcoverage',
'action' => 'index',
),
),
),
When trying the url xml/coverage/33, I believe 33 should map to id, as it doesn't match the regex of action and both are optional. And since it doesn't match an action, the default (index) should be used.
Instead I get an error saying that the url cannot be matched by routing.
So for me, it acts as if the route was '/xml/coverage[/:action[/:id]]' because I for some reason have to specify action for it to recognize the id.
What am I doing wrong, and how can I get the urls to work as I'd like?
Thanks.
EDIT: Here is a problem.
Doing this in my view:
$this->url('xmlcoverage', array('action' => 'index', 'id' => $someid))
actually gives an URL on the form xml/coverage/1 which will crash!
Changing the route to /xml/coverage[/:action[/:id]] will at least make the url helper produce working urls..
After talking and debugging with the nice ZF2 folks on IRC, we tracked down a bug in the routing.
During the discussion I made a small example to my issue, which is here.
As you can see from the var dump here, the action gets lost in the second case where it should default to "index".
But if anyone needs this functionality to work right now, here are ways that fix it:
Instead of having the route to be /test[/:action][/:id] have it to be /test[/:action[/:id]], then the url helper will add /index/ and at least it works.
Make a new route where you only listen for /test[/:id] in addition to the other one.
In your controller, do public function notFoundAction() { $view = new ViewModel($this->indexAction()); //etc} Kinda hacky, but with this bug it will dispatch a not found action, which you can piggyback.