Yii2 Variables to be passed in URL - rules not working - yii2

I have two actions with parameters. I have written two url rules, but only one works at a time. I don't know the issue. These are my acions,
Index action in Site Controller and other one is index action in Product Controller
public function actionIndex($language = null) {
/* some codes */
}
public function actionIndex($id= null) {
/* some codes */
}
'rules' => [
'<language>' => 'site/index',
'<id>' => 'product/index',
]
The above are my url rules.But only the first rule is working. What is the issue?

Your rules are ambiguous. '<language>' pattern will match every URL, so second rule will never be reached. You should either create different URL structure for these two rules:
'rules' => [
'<language>' => 'site/index',
'id/<id>' => 'product/index',
],
Or use different patters (only literal languages and numerical IDs):
'rules' => [
'<language:[a-z]+>' => 'site/index',
'<id:\d+>' => 'product/index',
],

Related

Yii2 - Understanding urlManager

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']);

Syntax for defining rules for routes in yii2

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.

yii2 SluggableBehavior is applied to only emty slug field

I am using SluggableBehavior in such way
public function behaviors()
{
return [
[
'class' => SluggableBehavior::className(),
'attribute' => 'name',
'slugAttribute' => 'alias',
],
];
}
It works nice If field 'alias' in form is empty.
How to ignore this behaviors If field alias is not empty on form submitting ?
thanks in advance !
Add 'immutable'=>true in the behavour config.
The behaviour works in such way, that if the slugAttribute is not empty when immutable is on, that attribute will not be changed.
Try something like:
Configure this behavior with specific name:
return [
'slug' => [
'class' => SluggableBehavior::className(),
'attribute' => 'name',
'slugAttribute' => 'alias',
],
];
In controller load attributes from the form (before validation).
Check if alias attribute is empty.
If it is not - detach this behavior ($this->detachBehavior('slug')).
Validate model.

Yii2 create user friendly URL with parameters

Hi I've to create user friendly URL but when using with parameters it's not working.
Url:
Url::to(['site/index', 'id' => 1]);
url looks like :
localhost/testApplication/frontend/web/index.php/site/index?id=1
/forntend/config/main.php
'urlManager' => [
'class' => 'yii\web\UrlManager',
'enablePrettyUrl' => true,
//'showScriptName' => false,
'rules' => [
],
],
I want a output like
localhost/testApplication/frontend/web/index.php/site/index/id/1
and after that how to access id value in controller.
'rules' => [
'site/index/id/<id:\d+>' => 'site/index'
//'site/index/<id:\d+>' => 'site/index' Better solution
//'<controller>/<action>/<id:\d+>' => '<controller>/<action>' Will be applied for all controllers and actions
],
Routing Doc.
And after in your action :
public function actionIndex($id)
{
...
}
Is really strange, for me using the parameter 'id' always show errors, I needed to change the parameter to 'user_id', but in other parts of the code I could use, really don't know why, but try to rename the parameter.

Problems with Yii2 Rules creation

I have a Yii2 with Yii2 admin, user andAdminLTE installed. My problem is I don't know how to create rules, actually I don't know how to define the Class Name. Where "Classes" should be defined? How can I see which Classes do I have or add Classes?
Thanks a lot,
I don't know what is that module that you use but i know how to define rules for controller.please open a controller for example : mycontroller.
when you want create a rule for action in your mycontroller you should use the 'behaviors' function as you can see in bellow.
class MyController extends Controller {
public function behaviors() {
return [
'access' => [
//you can use this class is use for every controller "AccessControl::className()"
'class' => AccessControl::className(),
// use this rules just for these two actions(logout and signup)
'only' => ['logout', 'signup'],
//this is your rules for your controller's actions
'rules' => [
[
'actions' => ['signup'],
'allow' => true,
// '?' is the default roles in yii2
'roles' => ['?'],
],
[
'actions' => ['logout'],
'allow' => true,
// '#' is the default roles in yii2
'roles' => ['#'],
],
],
],
];
}
i have two actions in this controller 'signup','logout'and i give roles to every actions.i give ? role to sign up and # role to logout.
? roles:means every user with out login can see this action.
# roles:means every user with login cans see this action.
as you can see the class in rules definition is static and you don't need to specify class you can just can use AccessControl::className() in your code.
best regards