Help With Urls
#1
Posted 13 February 2013 - 01:58 PM
I developed a site that has a super-simple content management system that allows an administrator to create/edit pages that are accessed at "url.com/index.php/event/event-id" where event-id is a text string. The page IDs are stored in a database. The Event controller handles the requests using the View action.
I'm trying to use this site as a framework for a new site, but the new site requires that the URLs not have "event" on the front of them. So I want what used to be "/index.php/event/event-id" to just be "/index.php/event-id". I've tried playing with URL rules in the URL manager in config/main.php and I've tried adding a View action to the Site Controller that forwards requests to the Event controller, both with no luck. In particular, when I try to use the View action in the Site controller, the "event-id" gets turned into a string containing the word "error", which then causes a CHttpException error saying the request is invalid - because "error" isn't an ID it can find in the database.
Like I said, I think there's probably a simple URL manager solution or something, but I can't get my head around it. Any ideas? Thanks.
#2
Posted 13 February 2013 - 02:30 PM
'<id:\w+>'=>'site/<id>' and '<id:\w+>'=>'event/<id>' and '<\w+>'=>'event/view'
None of these rules seem to have any effect at all. I read through the CUrlManager doc page and don't really understand why, and I don't understand why removing all the existing rules in main.php seems to have no effect either - I guess there must be default rules.
#3
Posted 13 February 2013 - 03:40 PM
If some of my examples are confusing due to changing which controller is handling the request, it's because I have my Site controller setup to handle the requests also. Event/view and Site/view can both handle it.
I tried the following rule, which works:
'about-us' => array('site/about-us', 'caseSensitive'=>false)However, I can't get it to work dynamically...I'm sure I'm just putting it in wrong:
'<\w+>' => array('site/about-us', 'caseSensitive'=>false)
or
'<pg:\w+>' => array('site/<pg>', 'caseSensitive'=>false)
or
'<\w+>' => array('site/view', 'caseSensitive'=>false)
#4
Posted 13 February 2013 - 05:36 PM
$event = Yii::app()->request->pathInfo;
That value contains the ID I need to look up in my "Event" table.
#5
Posted 13 February 2013 - 10:09 PM
#6
Posted 14 February 2013 - 03:19 AM
BStep, on 13 February 2013 - 03:40 PM, said:
'about-us' => array('site/about-us', 'caseSensitive'=>false)However, I can't get it to work dynamically...I'm sure I'm just putting it in wrong:
'<\w+>' => array('site/about-us', 'caseSensitive'=>false)
or
'<pg:\w+>' => array('site/<pg>', 'caseSensitive'=>false)
or
'<\w+>' => array('site/view', 'caseSensitive'=>false)First of all, \w means letter or number or underscore, but not a dash, so you'd rather need to use
[-\w]+
If to take it all together, that's what you need:
public function actionEvent($slug){
findPageBySlugIsHere($slug);
}
'<slug:[-\w]+>'=>'event/view'The second approach I prefer to use in such a case - is to build url rule dynamically, based on actual slugs (event-ids) stored in db.
This way only URLs with existen slugs (event-ids) will be handled by the url rule.
I'll just provide piece of my code with my names:
class UrlManager extends CUrlManager
{
/**
* Initializes the application component.
*/
public function init()
{
$this->setRules();
parent::init();
}
/**
* Sets application url rules
*/
protected function setRules()
{
// add text pages support
$pages = CHtml::listData(Text::model()->findAll(array(
'select'=>'slug',
'condition'=>'`type`=:type',
'params'=>array(':type'=>Text::T_PAGE)
)), 'slug', 'slug');
if($pages){
$this->rules = array_merge(
array('<slug:('.implode('|', $pages).')>' => 'site/page'),
$this->rules
);
}
}
}
In your config file don't forget to change urlmanager component class:
[size=2]
[/size]
'urlManager' => array(
'class'=>'UrlManager',
....
#7
Posted 14 February 2013 - 11:23 AM
The following rule works for me now:
'<id:[-\w]+>'=>'site/<id>'
I tried to implement some code like yours for a custom UrlManager:
<?php
class QUrlManager extends CUrlManager
{
/**
* Initializes the application component.
*/
public function init()
{
$this->setRules();
parent::init();
}
/**
* Sets application url rules
*/
protected function setRules()
{
$criteria = new CDbCriteria();
$criteria->select = 'id';
$slugs = Event::findAll($criteria);
foreach($slugs as $slug)
{
$this->rules[] = array($slug,'site/'.$slug);
}
}
}
When I attempt to access a page after implementing that code and setting main.php to use that class for the UrlManager, I get the following error:
Quote
I can't find anything helpful on Google for that. Having the URL rule correct is "good enough" but if you have any insight on that error, I'd appreciate it.
#8
Posted 14 February 2013 - 03:06 PM
Event::model()->findAll($criteria)?
And what looks a bit strange to me is how your final url rules look (even working one): do you have actions that named according to event-ids from db?
Third, I think you're setting dynamic url rules a bit wrong way. Should be something like:
$this->rules['<id:('.implode('|', $slugs).')>'] = 'controller/action';Replace controller/action with your actual names and please notice with such approach $slugs must be an array. Just study the example I sent you more carefully.
#9
Posted 14 February 2013 - 03:35 PM
Edit: I understand your question better now. No, I don't have a separate action for each id/slug in the database. I'm honestly not sure why it even works with that rule, now that you mention it.
I see how your rule works now. I thought the CHtml piece was a little bit of a long way around to solve the problem, so I skipped your rule line. What I'm doing is writing a separate rule for each URL, but you're probably handling it more efficiently by adding every ID to one rule.
I'll try these suggestions and post again.
#10
Posted 14 February 2013 - 03:44 PM
<?php
class QUrlManager extends CUrlManager
{
/**
* Initializes the application component.
*/
public function init()
{
$this->setRules();
parent::init();
}
/**
* Sets application url rules
*/
protected function setRules()
{
$criteria = new CDbCriteria();
$criteria->select = 'id';
$events = Event::model()->findAll($criteria);
foreach($events as $event)
$slugs[] = $event->id;
$this->rules['<id:(' . implode('|', $slugs) . ')>'] = 'event/view';
}
}
#11
Posted 14 February 2013 - 04:26 PM
It's working.
[code]
Great
#12
Posted 15 February 2013 - 05:07 AM
#13
Posted 15 February 2013 - 11:51 AM
Do you have a suggestion relating to the "expensive" comment? It seems to load quickly and it'll be a low-traffic site, so it shouldn't be a problem, but I'd like to learn if you have a thought on it.
I'm the only one who has the ability to insert the event ids into the database, so I don't think I need to do any filtering on them unless that changes.
#14
Posted 15 February 2013 - 12:44 PM
#15
Posted 17 February 2013 - 03:36 AM
So, while this solution might work for you, I'm under the impression a lot of technical debts were gathered here. So, some advice from my side:
- Extend CBaseUrlRule instead of CUrlManager to set your own custom URL rule in place
- Use DAO instead of ActiveRecords to fetch the event ids
- Set some caching mechanism in place so the regex doesn't need to be regenerated on each and every request

Help














