urlManager: How do I use my own URLs stored in database?

Hi,

In my table I have an attribute "url" where I store the text for the url of each dataset (each dataset is shown in a view).

The url rule


'<url>'=>'category/view',

gets me the url "domain.com/blabla.htm" (which is exactly what I want). But this results in "Error 400 - Your request is invalid."

If I use


'<id>'=>'category/view',

it’s working.

I assume Yii isn’t looking in the url column in the table to get the corresponding dataset. How can I teach Yii to do so? Do I need to create a custom url class?

You need to read up on Url Management. What you want to do is perfectly possible (with Yii 1.1.8, possibly including an update for enhanced functionality).

I created a behavior to add to my main application class which intercepts the beginning of request processing, to add url rules from a database to the url rules array.

However, without wishing to be patronizing, unless you understand fully how url rules work in the url manager (both for interpreting and for creating urls), then I don’t think it will help you me explaining what I did (for example, Yii will not look for something in a database unless it is told to do so).

Please have a read, and then post any questions you have about particular aspects that you find difficult (if so).

I did read the URL Management Tutorial. The hint to create a behaviour helps me as I didn’t had this in mind. I will try this. Thanks.

Well just in case this helps you then, this is my behavior (which relies on a DbUrlRule model to retrieve the rule parameters from the database):


class RRUrlRuleDbBehavior extends CBehavior {

	public $urlRuleClassAlias = 'ext.RRUrlRule';

	

	public function events() {

		return array_merge(parent::events(), array(

			'onBeginRequest' => 'beginRequest',

		));

	}

	

	public function beginRequest($event) {

		Yii::import($this->urlRuleClassAlias);

		$x = strripos($this->urlRuleClassAlias, '.');

		if ($x === false) {

			$urlRuleClass = $this->urlRuleClassAlias;

		}

		else {

			$urlRuleClass = substr($this->urlRuleClassAlias,  + 1);

		}

		$rules = call_user_func(array($urlRuleClass, 'model'))->enabled()->findAll();

		$urlRules = array();

		foreach($rules as $rule) {

			$urlRules[] = $rule->criteria;

		}

		$this->owner->urlManager->addRules($urlRules, false);

	}

}

Obviously it was made for my use so will contain options etc that will not work generally.

Thanks for your example. I did it in another way now: After consulting the tutorial again I had a closer look to custom rule classes and gave it a try. (It’s available since 1.1.8 ) I have to admit that I’m really new to Yii, so it takes some time to connect all my grey cells :) In the End I could achieve what a wanted.

But…

I have another problem now: It takes ages to load a page (about 2-3 seconds, sometimes it’s faster, sometimes it’s slower).

This is the code for parsing the URL in my custom url class (function parseUrl):




// after pregmatch I look for the id in the db

$req = Yii::app()->db->createCommand("SELECT id FROM category WHERE url = '" . $matches[0] . "'");

$category = $req->queryRow();


if(isset($category['id'])) {

return 'category/view/id/' . $category['id'];

}



Does anyone know how to make it faster? Maybe Caching would help here? (Another topic I didn’t dig in so far…)

UPDATE: I just recognised, that other projects are also running slow. Maybe just a temporary performace issue of the server. Good answers are still welcome :D

Custom rules are one way to go, if you want different parsing. For myself I wanted to continue using the default Yii parsing but jhust be able to add rules dynamically, which is what my behavior allows.

As for the slowness, certainly check that it’s not the server first. Also, bear in mind that processing url rules is quite expensive, so if your database rule adds lots of rules to the rules array, then that might cause slowness.

It was the server. Today the speed is better.

If I need some day to add rules dynamically, I know now where to look :) Thanks for your help!