Prefix routing

I am writing a bug tracker using Yii (of course) which I want to behave as follows:

Every action for which there is a model with a related project model, I want to have an url prefixed with ‘projects/project_name’.

For example:

projects/projectOne/roadmap

projects/projectOne/issues

I can map that using a CUrlManager, like this:


class ProjectCUrlManager extends CUrlManager {

	

	public function createUrl($route,$params=array(),$ampersand='&') {


    	if (isset($params['project_identifier']) && $params['project_identifier'] == "__EMPTY__") {

        	unset($params['project_identifier']);

    	} elseif (!isset($params['project_identifier'])) {

        	$params['project_identifier']=Yii::app()->ProjectManager->GetActiveProject();

    	}

    	return parent::createUrl($route, $params, $ampersand);

	}




The ‘ProjectManager’ would be a CApplicationComponent.

I think I have the URL rules down, but then I need to grab the active project.

What’s the best way to do that?

I’ve thought of using model->hasAttribute(‘project_identifier’), but then I need a way to make my models store the current project_identifier (name) using their project_id attribute.

Am I on the right track? :)

I want this to happen for most actions, except for Issues.

Am writing a Redmine clone, by the way. ;)

To make sure you understand what I mean, this url:


projects/projectOne/issues

will call the index action of the Issues controller with a filter of ‘project_identifier’ - that is: all issues which are related to the project with the identifier passed in.

I am aware that the conventions of Yii states that controller names are singular, but that doesn’t matter here.

So the application has to check what the current project is, and pass the right project_identifier param.

Have any of you solved the same puzzle before? :)

I wonder why you don’t use the built in url rules. Shouldn’t something like this work?




 '/projects/<name>/<_a:(roadmap|issues)>'   => 'project/<_a>',



In your ProjectController you could then have actionRoadmap, actionIssues, etc. I often use getters to fetch a specific model from GET parameters:




public function actionRoadmap($name) 	// makes sure, $_GET['name'] is set

{

    $project=$this->getProject(true); 

    //...

}




public function actionIssues($name) 	// makes sure, $_GET['name'] is set

{

    $project=$this->getProject(true); 

    //...

}





// Query for the current project by GET parameters

private function getProject($required=false)  

{

    $project=Project::model()->find('name=?',array($_GET['name']));

    if ($required && $project===null)

        throw new CHttpException(404,'Project not found!');


    return $project;

}

Thanks, Mike.

Yes, that’s probably the easiest way of doing this.

Redmine doesn’t do that, my previous version using CakePHP didn’t do that, but I see that the other Redmine porting project has done the same thing.

That would simplify a lot of things. ;)

I’ll give it a shot, and come back if I face problems.