Sunday, January 12, 2014

Cascade create a model and attach it to another model in Controller in a One-to-Many relationship (Yii)

Suppose we have a situation where we a set of users, each of which belong to a particular project. In Yii, we already create two models, namely Project and User. The User model class contains an attribute project_id, which is the id attribute value of the associated Project model. Now a user cannot be created without knowing the project_id it is associated with

Step 1:

In the protected/views/project/view.php, add a link to create user associated with the project:

<?php echo CHtml::link(CHtml::encode('Create user under the project'), array('user/create', 'project_id'=>$model->id)); ?>
The project_id allows the UserController (i.e. the controller associated with the User model) to identify the project_id to which the created user should be associated with.

Step 2:

In the protected/controllers/UserController.php, add a private member variable _project:

private $_project = null;

Next in the UserController.php, find the method filters(), and add one line for projectContext filter:

/**
 * @return array action filters
 */
public function filters()
{
 return array(
  'accessControl', // perform access control for CRUD operations
  'projectContext + create index admin', //check to ensure valid event context
 );
}

Next in the UserController.php, defines the following methods:

public function filterProjectContext($filterChain) 
{
 //set the project identifier based on either the GET or POST input
 //request variables, since we allow both types for our actions 
 $project_id = null;
 if(isset($_GET['project_id'])) 
  $project_id = $_GET['project_id'];
 else
  if(isset($_POST['project_id'])) 
   $project_id = $_POST['project_id'];
 $this->loadProject($project_id);
 //complete the running of other filters and execute the requested action
 $filterChain->run();
}

protected function loadProject($project_id) 
{ 
 //if the project property is null, create it based on input id 
 if($this->_project===null) 
 {
  $this->_project=Project::model()->findbyPk($project_id); 
  if($this->_project===null)
  { 
   throw new CHttpException(404,'The requested project does not exist.'); 
  }
 }
 return $this->_project;
}
The above method allows Yii code to create and assign the _project with the content from database using the project_id passed in from Step 1. As a result, before the actionCreate() method is invoked, the _project is already properly initialized based project_id attribute passed in. The final step is to assign $user->project_id in the actionCreate() method of the UserController class, as shown below:
public function actionCreate()
{
 $model=new User;
 $model->project_id=$this->_project->id;

 // Uncomment the following line if AJAX validation is needed
 // $this->performAjaxValidation($model);

 if(isset($_POST['User']))
 {
  $model->attributes=$_POST['User'];
  if($model->save())
   $this->redirect(array('view','id'=>$model->id));
 }

 $this->render('create',array(
  'model'=>$model,
 ));
}

No comments:

Post a Comment