How to use Yii2 Sluggable Behavior without showing id number? - php

I have read the question on using SluggableBehavior in Yii2
and in my trial case I can generate url like article/1/First-Article using the rule in urlManager
'article/<id:\d+>/<slug>' => 'article/view',
and using
\yii\helpers\Url::to(['article/view', 'id'=>$model->id, 'slug'=>$model->slug])
to create url.
In my real case, I use ['article/view', 'hash'=> $model->hash, 'slug'=>$model->slug] to generate url. My rule is
'article/<hash:[\d-\w]+>/<slug>'=>'article/view'
My url is like article/1e482d69129d760e9494b2c6e86eba2b/First-Article.
I want to only show url like article/First-Article, i.e. not showing the hash code in the url. Is there a way to achieve this? Thanks a lot!

According to Yii docs, if your specify SluggableBehavior's attribute property with an array of model attributes, it will implode (concatenate) them in order to generate uniqueness for the slug. In your case, this implementation perfectly satisfies your desired slug concatenated composition (e.g. First-Article-1);
Internally SluggableBehavior will perform it's generateSlug method to generate unique slug from your attributes composition defined in attribute property. Since generateSlug uses - delimiter by default, it perfectly fits your requirements in order to generate desired url slug.
Take a look into this:
public function behaviors()
{
return [
[
'class' => SluggableBehavior::className(),
'attribute' => ['slug', 'id'],
...
]
];
}
EDIT:
This is your URL Rule: 'article/<slug>' => 'article/view'
and
Generating appropriate link: Url::to(['article', 'slug' => $model->slug . '-' . $model->id])

Related

Yii2 Create Pretty URL like /index.php/viewName/actionName/var1/value1/var2/value2

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&param2=value2
at the moment, my url look like this:
index.php/xmple/test/?param1=value1&param2=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&param1=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'
],
],

Remove controller name from URLs in Yii2

How can I remove the controller name from URLs in Yii2?
I'm aware of simple aliases, but I'm not sure how to apply aliases to a little bit more complex rule, like the following one:
'rules' => [
'public/<seo_url:.*?>/<category_id:\d+>/<product_id:\d+>' => 'public/product'
]
This will create a rule so URLs like /product/this-is-a-slug/94/12 will call the actionProduct in my Public controller.
How can I make an alias that would call that same action if I try to access a product using this URL: /this-is-a-slug/94/12 ?
Set new rulw on top of all rules. Like that:
'rules' => [
'<seo_url:.*?>/<category_id:\d+>/<product_id:\d+>' => 'public/product',
]
This is work for me.

Routing rule in Yii?

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.

How can I hide user_id from URL using yii framework?

I am using the yii framework and have different user accounts. When I want to have a look at the view page of user 4 I have to enter an url like www.mydomain.com/user/4 for update I have www.mydomain.com/user/update/4.
Is there a way so that I can hide the user id from the url line?
How can I set a route like www.mydomain.com/user/username and www.mydomain.com/user/update/username? Do I have to modify the routes?
What if the username contains an # symbols?
If each user has a unique username, you can describe a route that doesn't show their user id by putting this custom routing rule in config/main:
'urlManager' => array(
'rules' => array(
'user/<username:\S+>' => 'users/view',
)
)
The \S+ should accept "#". Then pass that username to controllers/UsersController like so:
public function actionView($username) {...}
Instead of www.mydomain.com/user/update/username I would use www.mydomain.com/user/<username>/update and put this in the above urlManager rules array:
'user/<username:\S+>/update' => 'users/update',
and this in UsersController:
public function actionUpdate($username) {...}
You can also generate a unique, random number for each user before creation and route based on that number.
I think it's better to encrypt your id before passing it. And decrypt it when you reach there. There are many ways of generating such random/encrpted ids. For more security you should not give name like 'user', that you did. Try to modify that even. Hope you got the point...:)

Custom lithium routing scenario

I've been tasked with rewriting an existing website with large pre-existing link catalog. For argument's sake, let's assume we can't do anything that would change the link catalog. Here's a few examples of the link structure we're working with:
An item page would be:
www.domain.com/widgets/some-totally-awesome-large-purple-widget
A category sub page page would be:
www.domain.com/widgets/purple-widgets
A category parent page page would be:
www.domain.com/widgets/
A custom page may be:
www.domain.com/some-random-page
The various page types are too numerous to write individual Routers for.
Using Router::connect I can easily account for the first and second scenarios using something like:
Router::connect('/{:pageroot}/{:pagekey}', 'Pages::index');
In turn, the Pages::index method looks for entries in our database with the "key" of '/widgets/purple-widgets'.
However, the framework defaults to the '/{:controller}/{:action}/{:args}' route for pages like the third and fourth. I know that this is the correct behavior for the framework. Also, best practice would state that I should write the site to match this behavior. But, that isn't an option here.
What I need is a Router that would allow the third and fourth examples to function the same as the first. All examples should be sent to the Pages::index controller, which in turn queries a database using the URL path as a key.
If you don't have any convention in the URL for what is what, between page, item and category. I'd go with a very generic router.
Router::connect('/{:category}/{:page}/{:item}', 'Pages::any');
Router::connect('/{:category}/{:page}', array('Pages::any', 'item' => null));
Router::connect('/{:category}', array('Pages::any', 'page' => null, 'item' => null));
And in Pages::any() to search for the correct stuff. Is that category a page after all (example 4)? Is that page an item (example 1)?
or
You store the URL somewhere (e.g. a mapping table in the database) and use the pattern version of a lithium Route.
Router::connect(new Route(array(
'pattern' => '#^/(?<path>.+)$#',
'params' => array('controller' => 'pages', 'action' => 'any'),
'keys' => array('path' => 'path'),
// extra stuff, if the path is `tata`, it skips this route and uses
// any of the following ones that matches.
'handler' => function($request) {
if ($request->params['path'] == 'tata') {
return false;
} else {
return $request;
}
}
)));
From that point, you'll get the full URL.
You probably should write a smart Router Helper which is maybe able to process your request based on your db defined routes.
Take a look into: net/http/Router.php
especially connect(), parse() and match()
I would start to write some kind of anonymous function and progress it to a testable Class which is located in /extension.. ?

Categories