I have links such as:
http://host.com/auto/contacts/?name=mercedes&page=2
I write rule to link:
http://host.com/auto/contacts/?page=2
[ 'route' => 'auto/<action>',
'pattern' => 'auto-<id:\d+>/<action:[-\w]+>/page-<page:\d+>',
],
But how to write rule, when I using 2 parametres (?name=mercedes&page=2)?
Its similar like you write for one parameter:
'auto-<id:\d+>/<action:[-\w]+>/<name:\w+>/page-<page:\d+>'
But its limited to exactly that case when u have one parameter that will be 'name' and than 'page-x'. So if u will have later more parameters you will need to add new rule for matching them, or to create something more dynamic. I already explain in short how you can do with additional behavior when u have lot of categories and sub-categories here
You can do something similar with dynamic parameters also.
I hope this help you to get some idea.
Related
i am playing around with yii2 (recently been working in Yii 1.3) and need help to configure/write the Url-Manager Rules for my favorite URL-sheme.
As Example, i wanna call the action test from xmpleController with 2 parameters.
a normal GET request would looks like this:
?param1=value1¶m2=value2
at the moment, my url look like this:
index.php/xmple/test/?param1=value1¶m2=value2
This is how the url should look like:
index.php/xmple/test/param1/value1/param2/value2
here are my URL-Manager Rules:
'urlManager' => [
'enablePrettyUrl' => True,
'showScriptName' => false,
'rules' => [
'<a:\w+>/<b:\w+>/<c:\d+>/<d:\d+>' => 'a/b'
],
],
Does anybody have an Idea how I can use my favorite URL scheme? I think the only way to reach my goal is to edit the urlManager rule, but I don't have any experience in this. maybe someone here has some hint for me?
Thanks for your help!
Before you start making your desired URL format you need to understand first what formats are supported by the URL manager when working in Yii2. And how to create rules to create those formats.
Supported URL Formats
The default URL format;
The default URL format uses a query parameter named r to represent the route and normal query parameters to represent the query parameters associated with the route. The URL /index.php?r=xmple/test¶m1=100 represents the route xmple/test and the param1 query parameter 100. The default URL format does not require any configuration of the URL manager and works in any Web server setup.
The pretty URL format.
Uses the extra path following the entry script name to represent the route and the associated query parameters. For example, the extra path in the URL /index.php/xmple/100 is /xmple/100 which may represent the route xmple/test and the param1 query parameter 100 with a proper URL rule. To use the pretty URL format, you will need to design a set of URL rules according to the actual requirement about how the URLs should look like.
This rule can satisfy the above statement 'xmple/<param1:\d+>' => 'xmple/test',
Read More about it here
So it is not going to be showing
index.php/xmple/test/param1/value1/param2/value2 but
index.php/xmple/test/value1/value2 or index.php/xmple/value1/value2 or xmple/test/value1/value2.
How to create Rules
You can configure yii\web\UrlManager::$rules as an array with keys being the patterns and values the corresponding routes.
Read More here
You can use the rule 'xmple/test/<param1:\w+>/<param2:\w+>'=>'xmple/test' considering that you will be sending parameters that match any word character (equal to [a-zA-Z0-9_]) as a parameter, which will output xmple/test/value1/value2 with 'showScriptName' => false, or index.php/xmple/test/value1/value2 otherwise.
If the rule is going to be used for a single controller/action or you can use as described or use the parameterized routes which allows a URL rule to be used for matching multiple routes.
You can change your urlManager to the following
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
'xmple/test/<param1:\w+>/<param2:\w+>'=>'xmple/test'
],
],
I have been looking around but haven't found what I needed. Basically, I have a few small modules which have just the DefaultController and a few bigger ones with multiple controllers.
My rules for the small modules work fine but the ones of the big modules won't. Here are my rules:
'<module:\w+>/<action:\w+>' => '<module>/default/<action>',
'<module:\w+>/<action:\w+>/<id:\d+>' => '<module>/default/<action>',
'<module:\w+>/<controller:\w+>' => '<module>/<controller>/index',
'<module:\w+>/<controller:\w+>/<action:\w+>' => '<module>/<controller>/<action>'
The first two rules work fine, allowing me to access:
http://host/news/create and routes to news/default/create.
The last two are supposed to do the following:
http://host/posts/category which should route to posts/category/index
and
http://host/posts/category/create which should route to posts/category/create
They do not seem to work, sadly. Any suggestions?
It looks like the first rule will capture any request that could also match the third one.
Think of it in the terms of its representing regex: w+/w+: as a generic rule for routes in Yii, more prescriptive rules should go on top and less more generic, catch-all rules should be at the bottom.
Now the best way to obtain what you need would be to do something along the lines of:
'<module:news>/<action:\w+>' => '<module>/default/<action>',
'<module:news>/<action:\w+>/<id:\d+>' => '<module>/default/<action>',
'<module:posts>/<controller:\w+>' => '<module>/<controller>/index',
'<module:posts>/<controller:\w+>/<action:\w+>' => '<module>/<controller>/<action>'
this way you are explicitly expressing the routes for each of the modules in a clear and immediate way which will also help you in the long-term.
I have a new question related to this question, but since the questions do not match at all, I am creating this new topic. But it is for good reference.
I changed my mind about the logs to log thing, logs is fine. But I am having another controller called WikisController, in this case I would really like to change the URL. I just hate it that the URL will be example.com/wikis/subject.html, I want it to be example.com/wiki/subject.html. It is much cleaner and the convention is now a 100% match with other sites where it is also called wiki, and not wikis. But, I want the controller to be called WikisController, because of the CakePHP convention.
Well, now comes the real problem. I was currently using the following routing in Config/routes.php:
Router::connect('/wiki/:action/*', array('controller' => 'wikis'));
Router::connect('/wiki/*', array('controller' => 'wikis'));
This is the piece of code used by the solution in the other topic. But now I am running into a little bit of trouble. Well, it isn't really a big issue because everything works just fine. But I don't like the URL.
When I create a link as the following from example.com/wiki/edit.html:
echo $this->Html->link('Wiki overview', array(
'controller' => 'wikis',
'action' => 'index',
'ext' => 'html'
));
It is creating a link to example.com/wiki/index.html totally fine and it works, but I don't want to show the index.html, I just don't. It is a word extra in the url and it is not necessary for the user to understand where he is.
I am creating the link with the controller and action key because of a little bug I was having earlier. When I didn't specify the action, it would create a link to example.com/edit.html which I don't want, obviously. So I have to add the action => index key to the array. I am not sure if this is a real bug, but it shouldn't matter. Index = index and nothing changes that. It is a good thing that I am sure my URL is pointing to the right page, so adding the action isn't an issue for me.
Just for good notice:
When I am creating a link on exactly the same way as I did above to example.com/flights/index.html from the page example.com/flights/add.html it would delete the /index part from the url and simply create a url to example.com/flights.html which is much cleaner.
So it has to do something with the routing, but I can't figure out what.
If I understood you correctly, then you'll need a route that connects /wiki to the controllers index action:
Router::connect('/wiki', array('controller' => 'wikis', 'action' => 'index'));
Router::connect('/wiki/:action/*', array('controller' => 'wikis'));
...
I have a stat, in which many can exist for an improvement, which is one model in my about page. I initially built the page as one giant controller having silly actions like "action_editimprovementstat".
So I tried to move things into directories, so rather than everything being in "[...]/controller/about", I moved things into there perspective folders, for example: "[...]/controller/about/improvement/stat"
I changed the regex of the route, so the controller would accept slashes, which judging by the debugger, worked, because now the controller text will show up as "about/improvement/stat", unfortunately it still tells me the requested url can't be found.
So, I ask, what is the simplest way to have a hierarchical controller structure?
Here is an example of controller URLs that I would prefer:
/about
/about/internal
/about/external
/about/improvement
/about/improvement/stat
Those would also have actions, so for example:
/about/improvement/edit/6
/about/improvement/stat/delete/7
I'm willing to compromise if there are issues with ambiguity.
(Btw, I think I could manage a way if I did my own routing through a single controller, but I'm wondering if there is a better way, or if that way is well documented [so I can learn from another's experience].)
You can simply add additional variables or constant values to the route if you live.
The Kohana documentation even shows a concrete example, where an extra directory is added in front of the route, which can have only one of two given values:
Route::set('sections', '<directory>(/<controller>(/<action>(/<id>)))',
array(
'directory' => '(admin|affiliate)'
))
->defaults(array(
'controller' => 'home',
'action' => 'index',
));
Of course you can add values in the back or inbetween as well. The only requirement is that your route will always result in at least a controller and an action. But they don't actually have to exist in the url. You can specify routes that match other values and have a constant value for controller and/or action, like this:
Route::set('search', ':<query>', array('query' => '.*'))
->defaults(array(
'controller' => 'search',
'action' => 'index',
));
The greatest pitfall: It is important to understand that routes are matched in the order they are added, and as soon as a URL matches a route, routing is essentially "stopped" and the remaining routes are never tried. Because the default route matches almost anything, including an empty url, new routes must be place before it.
Maybe that is what's going wrong now?
Anyway, rather than adding trickery to match slashes, I'd rather create a route that accepts a large number of optional variables, so you could read 'urlpart1' to urlpartX' from your generic controller. That is, if you need to. The setup, of course, is to let you create different controllers for different urls, so you don't need a humongous controller with a gigantic method to decide what to do based on the url parts.
Ever since I learned Kohana, my programming experience has been greatly improved because prior to Kohana I never gave a moments thought to how my urls were constructed. In the MVC world using Pretty URLs makes you really think about what you want to do and how to go about it.
In my opinion by looking at what you are wanting to do in the examples above, it seems to me that you are thinking backwards. You said the URLS that you preferred are: /about /about/internal /about/external /about/improvement /about/improvement/stat
It seems to me that "about" is really an action, not a controller. The url "/about/" is pretty confusing because it doesn't tell me what I'm getting information about but we can let that one slide because it's probably about the site in general. "/about/internal" is pretty clear but in a lot of ways you are trying to write your urls so that they read in proper English. In reality I would write them as: /about, /internal/about, /external/about, /improvement/about, /improvement_stat/about
I'm not sure why you are resisting have several controllers unless perhaps you are setting up your controllers as template controllers and maybe you think you have to do that for each one. You dont. In general I create a controller named "page" which is my template controller. Then all other controllers extend the page controller. I can define constants and other variables in the page controller that can be used in all the controllers that extend the page controller.
But if you are really resisiting writing multple controllers, you can always write specific routes that will let you reach any controller and action that you want. For example I used a route for a comparison where I wanted up to 4 id's passed into my route. I wrote that route like this:
Route::set('thing_compare', 'thing/compare/<thing1>/<thing2>(/<thing3>(/<thing4>))')
->defaults(array(
'controller' => 'thing',
'action' => 'compare'
));
Note that thing3 and thing4 are in parens which means they are optional. Then in my controller I can get those values by doing something like:
$thing1 = $this->request->param('thing1');
But going back to the examples you gave, just write the routes something like this (assuming your controller is named "about":
Route::set('about_internal', 'about/internal')
->defaults(array(
'controller' => 'about',
'action' => 'about_internal'
));
Route::set('about_external', 'about/external')
->defaults(array(
'controller' => 'about',
'action' => 'about_external'
))
Personally I would avoid setting routes like this and really reconsider how your urls need to be setup so that it creates a sensible design strategy.
I want that users can surf to http://www.yyy.com/xxx for xxx being a parameter. and so with www.yyy.com/xxx/zzz . I have following routing which works fine:
Router::connect('/:town', array('controller'=>'places', 'action'=>'index'), array('pass' => array('town')));
Router::connect('/:town/:category', array('controller'=>'places', 'action'=>'index'), array('pass' => array('town', 'category')));
But when I want tot surf to a different controller example www.yyy.com/differentcontroller/add it goes back to the places controller unless I make a routing for it...
any ideas?
The second rule on your routing list is simply looking for two sets of any combinations of characters after the domain name and treating the first as a town and the second as a category. As a result it mistakenly parses 'differentcontroller' as a town name and 'add' as a category. If you want to keep this URL structure then you'll need to add more specific routes to your routing file to cover situations like the 'add' route, or consider changing your existing URL layout to something more specific, like:
Router::connect('/places/:town', array('controller'=>'places', 'action'=>'index'), array('pass' => array('town')));
Router::connect('/places/:town/:category', array('controller'=>'places', 'action'=>'index'), array('pass' => array('town', 'category')));
My memories about cake routing is quite rusty, but you can use :controller/:action as a rule to make cake look for a valid controller/action pair, if I remember correctly.