[SOLVED] How to make NESTED SEF links?

Ok so now I know what slug means and how to create nice url

my initial question

SEF basics

write with yiibehavioursluggable

read slugs with dburlmanager

using-search-engine-and-user-friendly-urls

I learned how to create :

www.domain.com/direct-link-to-page

www.domain.com/post/99/direct+link+to+page

But how to create sef with pages nested within multiple categories like this?

www.domain.com/cars/2011/toyota/camry/20cc/showmethecar.html ??

Is this even necessary? I am on the verge of creating my own way of traversing through the categories in db to check for valid path, checking for number of slashes (/) and whats not but its a real hassle…

How is this being done? Should this even be done?

Wordpress has links like this

www.domain.com/2007/10/09/easy-way-to-generate-pdf-in-php/

Are the 2007/10/09 categories?

Hopefully some of you experts can point me to right direction.

dburlmanager can manage simpler URLs. It will not enforce, for example, that the post "my new car" is in the category "cars" in the URL


http://example.com/cars/my-new-car

It will only check if the category and the post exist.

But for an URL like the one below, it will work well.


http://example.com/my-new-car

PS:

Mind the database overhead!

And read the extension docs.

In (soon to be released) Yii 1.1.8 you’ll find support for custom UrlRule classes. They should probably make it easier to solve your problem. Check the new docs at the bottom of this page here:

http://code.google.com/p/yii/source/diff?spec=svn3235&old=3165&r=3236&format=side&path=%2Ftrunk%2Fdocs%2Fguide%2Ftopics.url.txt

Thank you! Yii is great!! especially the people behind it!!

But isn’t this a common problem that should already have some discussion/notes/hacks somewhere?

One hack is: add a rule for every depth level of your nested catogries, longest first:




'/cars/<category>/<subcat1>/<subcat2>/<subcat3>/<subcat4>' => 'cars/list',

'/cars/<category>/<subcat1>/<subcat2>/<subcat3>' => 'cars/list',

'/cars/<category>/<subcat1>/<subcat2>' => 'cars/list',

'/cars/<category>/<subcat1>' => 'cars/list',

'/cars/<category>' => 'cars/list',

but I wouldn’t know what and how many categories the users will create… can the string ‘/cars/<category>/<subcat1>/<subcat2>/<subcat3>/<subcat4>’ be dynamically generated from the db?

That’s what dburlmanager does.

You can study it and the 1.1.8 functionality and design your own extension to handle the URLs.

Can you provide some examples how to achieve that with dburlmanager?

I only see your sample :

http://mystore.com/blue-coffe-mug

http://myblog.com/my-first-post

You mean dburlmanager can already do this??

http://myblog.com/my-diary/2011/06/my-first-post/

How?

You’d better learn a bit from the extension and follow Mike’s tip.

You’ll find instructions at the extension page and on its forum topic.

Sorry I am still very new. Hope you can enlighten and bear with me :

As I understand it both 1.1.8 and dburlmanager "dynamic/custom rule" means the ability to validate slugs against the db BEFORE going into the controller. As opposed to a normal static rules that uses the Controller to check the db like using loadModel() and then throwing out error if the article is not found.

Nowhere did I see how both implementation traverse the path and checks the db if the path is a valid one, like :

www.domain.com/cars/2011/toyota/camry/20cc/showmethecar.html ??

IS "show-me-the-car" page exist in "20cc"?

then check

IS "20cc" a valid entry in "camry" category?

then checks

IS "camry" a valid entry in "toyota" category?

then check

IS "toyota" a valid entry in "2011" category?

And throw out error at any point a category do not exist in any categories…

Creating rules like ‘/cars/<category>/<subcat1>/<subcat2>/<subcat3>/<subcat4>’ => ‘cars/list’,

means hard-coding the levels which might run 10 or more levels deep depending on how many categories the user creates…(its a CMS with unlimited number of nested categories)

and categories name (or its slugs) might have duplicates in separate folders like

www.domain.com/cars/2011/toyota/camry/20cc/showmethecar.html ??

www.domain.com/cars/2011/toyota/lexus/20cc/showmethecar.html ??

www.domain.com/cars/2011/honda/accord/20cc/showmethecar.html ??

So I need to check the validity of the full path.

Do you mean I should create hard-coded rules with as many as I "Guess" the level of subcategories will be? and create on subcat lesser on the next rule?




'/cars/<category>/<subcat1>/<subcat2>/<subcat3>/<subcat4><subcat5>/<subcat6>/<subcat7>/<subcat8>/<subcat9>/<subcat10> or more ..11?12?13?14?15?16?' => 'cars/list',

'/cars/<category>/<subcat1>/<subcat2>/<subcat3>/<subcat4><subcat5>/<subcat6>/<subcat7>/<subcat8>/<subcat9>' => 'cars/list',

'/cars/<category>/<subcat1>/<subcat2>/<subcat3>/<subcat4><subcat5>/<subcat6>/<subcat7>/<subcat8>' => 'cars/list',

etc

Or if using dburlmanager do I do this with as many levels I can think of?





<author:\w+>/<subcat1:\w+>/<subcat2:\w+>/<subcat3:\w+>/<post:\w+>'=>array(

         'post/view',

         'type'=>'db',

         'fields'=>array(

             'author'=>array(

                 'table'=>'tbl_author',

                 'field'=>'author_name'

             ),

             'subcat1'=>array(

                 'table'=>'tbl_post_category',

                 'field'=>'post_cat_slug'

             ),             

             'subcat2'=>array(

                 'table'=>'tbl_post_category',

                 'field'=>'post_cat_slug'

             ),      

             'subcat3'=>array(

                 'table'=>'tbl_post_category',

                 'field'=>'post_cat_slug'

             ),      

             'post'=>array(

                 'table'=>'tbl_post',

                 'field'=>'post_slug'

             ),

         ),

     ),                      

<author:\w+>/<subcat1:\w+>/<subcat2:\w+>/<post:\w+>'=>array(

         'post/view',

         'type'=>'db',

         'fields'=>array(

             'author'=>array(

                 'table'=>'tbl_author',

                 'field'=>'author_name'

             ),

             'subcat1'=>array(

                 'table'=>'tbl_post_category',

                 'field'=>'post_cat_slug'

             ),             

             'subcat2'=>array(

                 'table'=>'tbl_post_category',

                 'field'=>'post_cat_slug'

             ),      

             'post'=>array(

                 'table'=>'tbl_post',

                 'field'=>'post_slug'

             ),

         ),

     ),                      

<author:\w+>/<subcat1:\w+>/<post:\w+>'=>array(

         'post/view',

         'type'=>'db',

         'fields'=>array(

             'author'=>array(

                 'table'=>'tbl_author',

                 'field'=>'author_name'

             ),

             'subcat1'=>array(

                 'table'=>'tbl_post_category',

                 'field'=>'post_cat_slug'

             ),             

             'post'=>array(

                 'table'=>'tbl_post',

                 'field'=>'post_slug'

             ),

         ),

     ),

                




if it is as simple as this, then I could have just pass in all the $_GET[subcat1], $_GET[subcat2], $_GET[subcat3],etc into the controller "car/list" and check if each subcat belongs to the one above it…

so I the only difference I see using dburlmanager or Y implementation is that these path traverse validations are done BEFORE going into the controller.

But I guess I can’t hard code the rules with any given amount subcats.

How to create ONE "dynamic rule" that accept any level of subcats, and then check against the db for the existence of subcatX within subcatY either through dburlmanager or Y custom rule?

I need help or samples to help me better understand these things…

Thank you

Wow… thanks to this post and some time spent understanding Url Management and dburlmanager again and my lack of regex understanding…

This is what I need.




<category:[\w\/]+>' => 'catalog/index'



But I also having the same problem as the OP of the post

Is there any way to pass slashes without getting encoded? I have customized all the db path checking in @mentel dburlmanager under “function checkDbRule($manager)”. I can’t wait for 1.1.8

Yes! I did it by overriding createUrl in EDbUrlRule of dburlmanager!




	public function createUrl($manager,$route,$params,$ampersand)

	{

		if ($route==='category/list')

		{

			$category = $params['category'];

			$parts = explode('/', $category);

			

			$url = "";

	    for ($i=0;$i<sizeof($parts);$i++) {

        $url .= $parts[$i] . '/';

      }

      return $url;

    }

		return false;  // this rule does not apply

	}



@mentel, I modified alot of code in checkDbRule() to check the validity of the path. After checking the validity of the path, how do I send the valid category_id to the Controller to load the category?

I knew you could do it :)

In the new guide (in the link by Mike), it seems that you need to set the $_GET for the parameter name.

Tips: urlencode each param of the url and check PHP’s foreach.

Yii 1.1.8 is here already!