I'm new in Yii2 framework and I didn't understand how rules in urlManager work.
I have my url controller/action?id=1 and I want controller/action/id/ or controller/action/1. How can I do that with url management ?
Thanks !
If your argument is number then use this rule:
'<controller:\w+>/<action:\w+>/<id:\d+>' => '<controller>/<action>'
If your argument is text then use this rule:
'<controller:\w+>/<action:\w+>/<name:\w+>' => '<controller>/<action>'
You can use regular expressions in rules array.
This is example
'<controller:\w+>/<action:\w+>/<id:\d+>' => '<controller>/<action>'
Then in your controller you will get id like this
public function actionTest($id) {}
Related
I have these possible urls:
Having country at beginning:
peru/blog/search/my-search
peru/blog/tag/my-tag
peru/blog/my-blog-post
peru/blog/
peru/
Without Country at beginning:
blog/search/my-search
blog/tag/my-tag
blog/my-blog-post
blog/
/
How it works:
As I understand url management there are 2 processes:
When you write an url on the browser. In this case Yii tries to convert this url into a route and params.
When you are creating an url using Yii::$app->urlManager->createAbsoluteUrl, in example.
According to these, I am writing some rules in the urlManager, first the general config:
'urlManager' => [
'class' => 'yii\web\UrlManager',
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => []
]
Now the rules:
'<country:peru|france>/<module:[\w\-]+>/tag/<tag:[\w\-]*>' => '<module>/index',
'<country:peru|france>/<module:[\w\-]+>/search/<search:[\w\-]*>' => '<module>/index',
'<country:peru|france>/<module:[\w\-]+>/<slug:[\w\-]*>' => '<module>/index',
'<country:peru|france>/<module:[\w\-]+>' => '<module>/index',
'<module:[\w\-]+>/tag/<tag:[\w\-]*>' => '<module>/index',
'<module:[\w\-]+>/search/<search:[\w\-]*>' => '<module>/index',
'<module:[\w\-]+>/<slug:[\w\-]*>' => '<module>/index',
'<module:[\w\-]+>' => '<module>/index',
As you notice from the rules, I pass a parameter "module" in the url, and I want that one to be used as controller.
In the case of country I had to add some possible matches, if not I was not able to make it work.
With the above rules, It works when I input a "pretty" url on the browser like:
http://example.com/blog/search/my-search
But my issue starts If try to create an url:
Yii::$app->urlManager->createAbsoluteUrl(["blog/index", "module" => "blog"]
Rule: '<module:[\w\-]+>' => '<module>/index'
Url Expected: http://example.com/blog
Url Generated: http://example.com/blog?module=blog
It seems it does not fall in the rule, not sure.
If I try to create an url:
Yii::$app->urlManager->createAbsoluteUrl(['blog/index', 'module' => 'blog', 'slug' => 'my-post'])
Rule: '<module:[\w\-]+>/<slug:[\w\-]*>' => '<module>/index'
Url Expected: http://example.com/blog/my-post
Url Generated: http://example.com/blog/my-post?module=blog
From these 2 cases, I notice it is adding the controller to the url
Questions:
In my rule I use I think it collides with predefined variables like: , . I have tried change it, but still same issue.
In the case of country I had to add possible options: Peru, france to make it work, if not it did not work, how can I make it work without those options?
The url match depends on the amount of query params or does it count controller and action too?
How can I make empty parameters be ignored for the rules, when creating an url?
Why is adding controller to the url?
Is the rules order correct?
I think I found a solution to all my questions:
So far I have not found predefined keywords for rules: <controller>, <action>, <module> are just name of variables, if someone knows something different, please let me know.
Yii URL manager (and probably any URL manager) can only match the amount of parameters we send and match it against rules, not the variable names, so if we send:
http://example.com/peru
http://example.com/es
Yii only understands that we are sending one parameter, so if in the rules we have:
'<language:[\w\-]*>' => 'language/index'
'<country:[\w\-]*>' => 'country/index'
Yii will use the first rule that matches, so in this case would be <language> rule which will match. Then Yii will pass a variable $language with "peru" as value to LanguageControlle, which is wrong.
So in order to help Yii we have to add patterns to help it use correct rule, we could add a pattern to match only any value with 2 characters or specific values list like:
<language:es|en> => 'language/index'
<country:[\w\-]*> => 'country/index'
In this case if we have "peru" as value, it will not match first rule, so it will use second one.
Answered above.
Ignore empty parameters, we can use + instead of * in the rules, in that way empty parameters will not match.
Remove the controller, we need to add a rule at the end:
'' => 'site/index'
Question ordering, it should start with the rules with most parameters and inside that group order them from the less generic to more generic rules.
At the end my rules are:
'<base:es|en>/<module:ideas|user|blog>/tag/<tag:[\w\-]*>' => '<module>/index',
'<base:es|en>/<module:ideas|user|blog>/search/<search:[\w\-]*>' => '<module>/index',
'<base:es|en>/<module:ideas|user|blog>/<slug:[\w\-]*>' => '<module>/index',
'<base:es|en>/<module:ideas|user|blog>' => '<module>/index',
'<base:es|en>/<slug:contact>' => 'site/index',
'<base:es|en>' => 'site/index',
'<module:ideas|user|blog>/tag/<tag:[\w\-]*>' => '<module>/index',
'<module:ideas|user|blog>/search/<search:[\w\-]*>' => '<module>/index',
'<module:ideas|user|blog>/<slug:[\w\-]*>' => '<module>/index',
'<module:ideas|user|blog>' => '<module>/index',
'<slug:contact>' => 'site/index',
'' => 'site/index',
I hope this saves time to someone in the future.
The problem is how you create URL. If <module> is available in route pattern (value in rules array), then you don't need to pass it manually. It will be detected from route.
Sou you should create your URLs like this:
Yii::$app->urlManager->createAbsoluteUrl(['blog/index', 'slug' => 'my-post'])
Yii::$app->urlManager->createAbsoluteUrl(['blog/index']);
I am using Yii2's pretty urls and want to play around with the rules defined in my UrlManager but not finding any documentation as to how I can define variables in the 'pattern' => 'route' rule set. Found some examples like
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'enableStrictParsing' => false,
'rules' => [
"home" => "site/index",
"login" => "site/login",
"sign-up" => "site/sign-up",
'<controller:[\w-]+>/<id:\d+>' => '<controller>/view',
],
],
But what does the :[\w-]+ or the :\d+ stand for?
What if I wanted, for example, to define a pattern to point to my action which needs two parameters
class MyController extends Controller{
...
public function actionMyAction($param1, $param2){
...
}
}
now I want my web users to type in the url bar www.mysite.com/my-controller/my-action/X-Y where X is the value of $param1 and Y is the value of $param2 and using - as a parameter separator.
Thanks.
[\w-]+ and \d+ are regular expressions, the first indicating any letter or the dash character, repeated one or more times, the section indicating numbers only, repeated one or more times.
In the rule expression, you use <variable name:regex> to put a placeholder for your route that will resolve to variables passed to your controller action.
The rule should look like this if both $param1 and $param2 are numbers.
'my-controller/my-action/<param1:\d+>-<param2:\d+>' => 'my-controller/my-action',
Swap \d for \w if you need letters.
What will be the rules for my pretty url if I have the following scenario:
links like this where parameters may vary.
domain/?bt=<token>&e=<email>
or
domain/?lt=<token>&e=<email>
then should be processed in a controller/action. ie. mycontroller/get
Also, parameters should be accessible by $_GET inside the action.
the simplest way is based on the use of urlHelper
use yii\helpers\Url;
$myUrl = Url::to(['your_controller/your_action', 'bt' => 123, 'e' => 'myemail#gmail.com']);
Using the urlHelper function Url::to .. the url you need is properly formed depending of the urlManager configuration you have set in your config file
and the param a manager as show in the sample like entry in an array.
The post or get method is related to the type of metho you have in your ulr call if not other values are specified the url is formed as a get
and you can obtain the values you need in $_GET['bt'] and $_get['e']
http://www.yiiframework.com/doc-2.0/yii-helpers-url.html
http://www.yiiframework.com/doc-2.0/yii-web-urlmanager.html
http://www.yiiframework.com/doc-2.0/guide-runtime-routing.html
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
'<controller:\w+>/<id:\d+>' => '<controller>/view',
'<controller:\w+>/<action:\w+>/<id:\d+>' => '<controller>/<action>',
'<controller:\w+>/<action:\w+>' => '<controller>/<action>',
'' => 'call-backs/get',
'unsubscribes' => 'unsubscribes/get',
],
],
#scaisEdge, thank you for answering my question. maybe my question isn't that clear but this is the solution I made for my question after a hard find of clues and tips online.
All I wanted was that when a user clicks on a link, hitting the main page/main domain, it will go to my yii project (intended to be a webservice or an API like one) then will be handled by a precise controller and action.
'' => 'call-backs/get'
the code above answers the question. Cheers.
I am trying to make some url rules in Yii 2 so I can access an action from the controller like this:
controller/action/1 -> controller/action (with a parameter)
I tried some rules but they won't work in my modules (www.example.com/midend, www.example.com/backend).
So, if I want to access www.example.com/controller/action/1 it's works just fine but if I want to access www.example.com/midend/controller/action/1 it return 404.
These are the rules for modules:
'<module:\w+>/<controller:\w+>/<action:\w+>/<id:\w+>' => '<module>/<controller>/<action>',
'<module:\w+>/<controller:\w+>/<action:\w+>' => '<module>/<controller>/<action>',
'<module:\w+>/<controller:\w+>/<id:\w+>' => '<module>/<controller>',
These are the rules without modules:
'<controller:\w+>/<action:\w+>/<id:\w+>' => '<controller>/<action>',
'<controller:\w+>/<action:\w+>' => '<controller>/<action>',
'<controller:\w+>/<id:\w+>' => '<controller>',
I already tried to replace <module:\w+> with midend.
Assuming your ids are integers, you should simply replace your rules by this one :
'<controller>/<action>/<id:\d+>' => '<controller>/<action>',
It will work for :
www.example.com/controller
www.example.com/controller/action
www.example.com/controller/action/1
www.example.com/module (assuming you have a default controller)
www.example.com/module/controller
www.example.com/module/controller/action
www.example.com/module/controller/action/1
Normally a widget is used by calling CController::widget() on an instance of CController, typically $this in a view.
But if I'm writing a static method, a helper, say, then I don't have access to an instance of CController. So how do I use a widget?
Let's say further that this helper method is invoked in the eval()’ed expression in a CDataColumn's value property. That poor expression has almost no context at all. How should the helper use a widget?
EDIT: Code example
As requested, a view example:
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider' => $model->search(),
'columns' => array(
array(
'name' => 'attrName',
'value' => '--USE WIDGET HERE--',
),
)
));
This answer doesn't answer the question in general but in the specific case—how to access the controller and use a widget in the context of the evaluated expression of CDataColumn::$value—you can use this:
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider' => $model->search(),
'columns' => array(
array(
'name' => 'attrName',
'value' => function ($data, $row, $column) {
$controller = $column->grid->owner;
$controller->widget(/* ... etc ... */);
},
),
)
));
The trick was discovering that CDataColumn::renderDataCellContent() uses CComponent::evaluateExpression(), which injects the component instance into the callback as the last parameter. In this case that omponent is the CDataColumn, which references the controller as shown.
I don't like writing PHP expressions as string literals so I'm pleased to find this option.
A comment on http://www.yiiframework.com/doc/api/1.1/CDataColumn#value-detail shows another way to us a widget in a column value that I haven't tried.
This one is working solution for calling widgets in static methods in Yii
Yii::app()->controller->widget('widget');
There's no direct way to call a widget out of controller because you shouldn't do so. It's all about MVC. Widgets are only needed and/or useful in views, and views are only accessed via controllers. That's the theory.
I guess you're approaching the problem mistakenly. A proper, MVC-friendly way to do what your're trying to do involves using renderPartial(). You know: you a have certain content and you want to decorate it (in your case you want to imbibe it inside a widget, right?) before displaying it to final user; so, from the view, you call renderPartial(). It will send your data to a file where it will properly decorated. renderPartial() returns the content properly formatted and now you can display it in the view.
Unfortunately, in your particular case, you're working with grid view (right?) and, at least from my point of view, it makes the things a bit harder. In order to decorate content for a CGridColumn-subclass element (like CDataColumn), you need to override the renderDataCellContent() method. Check it out here: http://www.yiiframework.com/doc/api/1.1/CDataColumn#renderDataCellContent-detail