zf2 - url view helper: specify parameters for route - php

My main router goes like this (simplified):
'router' => [
'routes' => [
'blog' => [
'type' => 'regex',
'options' => [
'regex' => "/(?<language>[a-z]{2})?",
'spec' => "/%language%",
'defaults' => [
'controller' => 'Blog\Controller\Posts',
'action' => 'index'
],
],
'may_terminate' => true,
'child_routes' => [
// [...]
'add_post' => [
'type' => 'literal',
'options' => [
'route' => '/admin/post/add',
'defaults' => [
'controller' => 'Blog\Controller\Posts',
'action' => 'add'
]
]
], // end add post
] // end child routes
] // end blog route (main route)
] // end routes
] // end Router
And in the template displayed on "/en/admin/post/add" I have a call to $this->url(), that ends up printing /%language%/admin/post/add.
I have the language code available on $language on my template, and
I'd like to pass it on to url() so it properly constructs the the url using the spec.
Also, I'd like, if possible, not to specify the name of the route on my call to url(), so it uses the default one for $this.
How would I go around to accomplish this?
Thanks and regards

You could use a segment route instead of a regex one and then use
$this->getHelperPluginManager()->getServiceLocator()->get('request')->getUri()->getPath();
in your view to print the actual route it's been used

While #marcosh answer works, since then I've found a simpler solution:
$this->url($this->route, ['language' => $language]);
Will output what I want. Seems clearer to me.

Related

ZF2 - Controller managing route with and without params

I am writting an application with zf2 and I came to this issue which I don't know how to implement.
At the moment I have a router like this :
'routes' => [
'stock' => [
'type' => 'regex',
'options' => [
'regex' => '/stock(?<sku>\/.*)',
'defaults' => [
'controller' => MyController::class,
'action' => 'check',
],
'spec' => '/path%path%'
],
So when my url contains ../stock/13567/2312 the parameter gets passed into the checkAction function.
However, I would like to show a different content when the url is just ../stock/ or ../stock without any parameter sent. How can I achieve this ?
Thanks.
If you want to show different content depending if sku parameter is passed you can do following thing in your controller:
public function indexAction()
{
// Return sku parameter if exists, false otherwise
$sku = $this->params('sku', false);
if ($sku) {
// For example get single item
...
$view->setTemplate('template-a');
} else {
// Get all items
...
$view->setTemplate('template-b');
}
return $view;
}
Just augment the regex to mark the param as optional, as in the docs:
'regex' => '/stock(?<sku>\/.*)?'
... and don't forget to provide the explicit default value:
'defaults' => [
'controller' => MyController::class,
'action' => 'check',
'sku' => '' // or else
],

Zend multiparam URL to one parameter

Is there any solution to create this URL in Zend and get more URL parts as 1 parameter?
Ex.: /someApp/someFolder/Separator/Need/This/As/One/param/
and I need "Need/This/As/One/param" as 1 parameter...
My basic route is
"someApp/someFolder/Separator/:path/"
, I've tried something like
".../:path/*"
,... but nothing works ok. There will be no other param on the end of URL so it should be ok.
It get string after site/. For example: site/Need/This/As/One/param. variable path will have string Need/This/As/One/param
'type' => 'Segment',
'options' => [
'route' => 'site/:path[/]'
'defaults' => [...],
'constraints' => [
'path' => '.+',
]
]
]

Yii2 route using yii\rest\UrlRule with several parameters

I am trying to use Yii 2 routing for REST API.
Following tutorial at http://www.yiiframework.com/doc-2.0/guide-rest-routing.html, I have already defined (with success) a lot of rule for API entry point like so :
'urlManager' => [
'enablePrettyUrl' => true,
'enableStrictParsing' => true,
'showScriptName' => false,
'rules' => [
[
'class' => 'yii\rest\UrlRule',
'controller' => 'user'
],
],
]
Such a rule defines :
GET /users (list users)
GET /users/123 (show detail of user 123)
Now, my users have games. So I'd like to have urls :
GET /users/123/games (list games of user 123)
GET /users/123/games/864 (details of game 864 for user 123 - such as his scores)
I tried defining my new entry point (withhout success) like so:
'rules' => [
... previous rules ...,
[
'class' => 'yii\rest\UrlRule',
'controller' => [
'game'
],
'tokens' => [
'{userid}' => '<userid:\\d>',
'{gameid}' => '<gameid:\\d>',
],
'patterns' => [
'GET,HEAD /users/{userid}/games' => 'index',
'GET,HEAD /users/{userid}/games/{gameid}' => 'view',
]
]
]
This definition seems wrong because I get a 404 Page not found error.
How should I define my new url routes ?
I would like to use an equivalent format for my definitions, extending 'yii\rest\UrlRule'
I am not sure if this is even possible, the tutorial not mentionning this case.
So I figured out how to use more complex rules.
First, the solution, then the explanation.
Here is the solution:
'rules' => [
... previous rules ...,
[
'class' => 'yii\rest\UrlRule',
'controller' => 'game',
'prefix' => '/users/<userid:\\d+>',
'tokens' => [
'{gameid}' => '<gameid:\\d+>',
],
'patterns' => [
'GET,HEAD' => 'index',
'GET,HEAD {gameid}' => 'view',
]
]
]
And now the explanation:
First my userid / gameid attributes were badly defined. There was a missing "+" after "\d"
The controller seems to be automatically added as a prefix to the patterns. So you have to define both a controller and a prefix (that will be added before the controller).
Parameters in the prefix does not seem to be parsed to find tokens. So I wrote directly the regexp in the prefix instead of adding "userid" as a token.
Finally, there are various "/" automatically added during concatenation of "prefix/controller/pattern" so you don't have to write one.
Do not forget the pluralization rule too ! "game" is singular" but valid urls will be
/users/123/games
/users/123/games/789
Hope it will help.
I think there´s a simple solutions, please try this:
'rules' => [
...
'/users/<userId:\\d+>/games' => 'game/index' ,
'/users/<userId:\\d+>/games/<gameId:\\d+>' => 'game/view' ,
....
];
Just use yii2-nested-rest
It provides REST API for MANY-to-MANY relations in Yii2 framework.
Hope comments will make the magic more understandable:
'rules' => [
// this usual rule for base Yii2 rest usage
['class' => 'yii\rest\UrlRule', 'controller' => ['sitecomponent' ,'sitepage' , 'sitedomain'], 'pluralize'=>false
],
// then rules for yii2-nested-rest
[
// url sitepage/NNN/sitecomponent[/MMM]
// ^^^^^^^^^ ^^^^^^^^^^^^
// resourceName model-endpoint
'class' => 'tunecino\nestedrest\UrlRule',
'modelClass' => 'app\models\SitePage',
'resourceName' => 'sitepage',
'relations' => ['components' => ['sitecomponent'=>'sitecomponent'] ],
// ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^
// relation name url-endpoint controller]
// defined in model SitePage model-endpoint with Actions from nested
],
[
// cross url sitecomponent/NNN/sitepage[/MMM]
'class' => 'tunecino\nestedrest\UrlRule',
'modelClass' => 'app\models\SiteComponent',
'resourceName' => 'sitecomponent',
'relations' => ['pages' => ['sitepage' => 'sitepage'] ],
// ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^
// relation name url-endpoint controller
// from model SiteComponent model-endpoint with Actions from nested
],
],
GET xx.com/v2/publication/12/p/34
[
'class' => 'yii\rest\UrlRule',
'pluralize' => false,//controller是否复数
'controller' => 'v2/publication',//此处一定要加上v2
'tokens' => [
'{id}' => '<id:\\d[\\d,]*>',
'{phase}' => '<phase:\\d[\\d,]*>',
],
// 通过extraPatterns和tokens来实现多个参数传递
'extraPatterns' => [
'GET,HEAD {id}/p/{phase}' => 'phase',
],
],
IN ACTION
public function actionPhase($id, $phase){}

ZF2 Literal Routes are not being matched

I am trying to set up Zend Framework 2 with multiple site specific modules. Each module configuration includes its own uniquely named literal path route. However, these routes are always ignored in favor of the "home" route in the application module. The URL points to the physical location of the index.php file for ZF2.
So, URL: localhost/zend/module/name/public/
config:
'routes' => array(
'moduleByPath' => array(
'type' => 'Literal',
'options' => array(
'route' => '/zend/module/name/public/'
),
'may_terminate' => true,
'child_routes' => $childRoutes,
),
),
But, I get matched to "home" as defined in the default Application. If I change the home route from '/' to '/doesntexist/' I get an error that the path doesn't match routing.
The module is being included correctly, as I can add a route to match by domain and everything loads correctly.
ZF2 'Literal' routes do not match up to physical directories, it just means a literal URI, rather than a 'Segment' URI for example that can take parameters like :action or :controller etc.
To make that route work in the example, you would need to move index.php up to the root /, ensure .htaccess is working correctly and remove the 'zend' physical directory and all subdirectories completely.
This will then cause ZF2 to map the literal URI /zend/module/name/public/ to that route 'moduleByPath', and process child_routes where necessary.
Also, normally for Literal routes you would declare a default controller and action that should load for this URI like this:
<?php
return [
'routes' => [
'api' => [
'type' => 'Literal',
'options' => [
'route' => '/api',
'defaults' => [
'controller' => 'api',
'action' => 'index',
],
],
'may_terminate' => true,
'child_routes' => [
// ...
]
]
]
];
For example. Ensuring you have the controller 'api' declared as invokeable in the config too:
<?php
// ...
'controllers' => [
'invokables' => [
'api' => 'MoudleName\Controller\ApiController'
// ... other invokables
]
]
Hope this helps, let me know if i'm not making sense :) Happy coding

ZF2 optional route constraints in child routes

I'm having an issue with an optional constraint in a route that is non-optional in it's children. My routing structure is as follows:
'profile' => [
'type' => 'segment',
'options' => [
'route' => '/profile[/:id]',
'constraints' => ['id' => '[0-9]*'],
'defaults' => [
'controller' => 'User\Controller\User',
'action' => 'profile'
]
],
'may_terminate' => true,
'child_routes' => [
'sessions' => [
'type' => 'literal',
'options' => [
'route' => '/sessions',
'defaults' => ['action' => 'sessions']
]
]
]
]
Which to my mind should give me the following routes:
/profile - works
/profile/123 - works
/profile/sessions - doesn't work
/profile/123/sessions - works
When I use route 3 in the URL view helper I get the following error:
$this->url('profile/sessions');
Zend\Mvc\Router\Exception\InvalidArgumentException: Missing parameter "id"
I originally had [0-9]+ as my constraint but making it optional (*) doesn't seem to have helped. Has anyone experienced this case before?
Add it to your parent route.
'profile' => [
'type' => 'segment',
'options' => [ // ↓
'route' => '/profile[/:id][/:action]',
'constraints' => [ 'id' => '[0-9]*', 'action' => '[a-zA-Z][a-zA-Z0-9_-]*' ],
'defaults' => [
'controller' => 'User\Controller\User',
'action' => 'profile',
],
],
]
This will make it optional to have id and/or action.
At least in theory it should make all your listed routes possible, there have been some issues with this.
I had the same issue once, the only solution I found was to create a separate route (in your case for /profile/sessions) as the optional parameter for the base route, seems to become obligatory when accessing a child route.

Categories