store foreignkey for both models

Hello All,

I have a database like this 

    =========== Group ===========

    id

    name

    

    ========== Member ===========

    id

    group_id

    firstname

    lastname

    membersince

Now I can save the two models in a form using this refernce site. Now my problem is that when I am going to save it is saving only the models but the foreignkey is not saving at all.





Here is the code for models

Group Model


<?php


/**

 * This is the model class for table "{{group}}".

 *

 * The followings are the available columns in table '{{group}}':

 * @property integer $id

 * @property string $name

 */

class Group extends CActiveRecord

{

  /**

   * Returns the static model of the specified AR class.

   * @param string $className active record class name.

   * @return Group the static model class

   */

  public static function model($className=__CLASS__)

  {

    return parent::model($className);

  }


  /**

   * @return string the associated database table name

   */

  public function tableName()

  {

    return '{{group}}';

  }


  /**

   * @return array validation rules for model attributes.

   */

  public function rules()

  {

    // NOTE: you should only define rules for those attributes that

    // will receive user inputs.

    return array(

      array('name', 'length', 'max'=>80),

      // The following rule is used by search().

      // Please remove those attributes that should not be searched.

      array('id, name', 'safe', 'on'=>'search'),

    );

  }


  /**

   * @return array relational rules.

   */

  public function relations()

  {

    // NOTE: you may need to adjust the relation name and the related

    // class name for the relations automatically generated below.

    return array(

      'member' => array(self::HAS_MANY, 'Member', 'group_id'),

    );

  }


  /**

   * @return array customized attribute labels (name=>label)

   */

  public function attributeLabels()

  {

    return array(

      'id' => 'ID',

      'name' => 'Name',

    );

  }


  /**

   * Retrieves a list of models based on the current search/filter conditions.

   * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.

   */

  public function search()

  {

    // Warning: Please modify the following code to remove attributes that

    // should not be searched.


    $criteria=new CDbCriteria;


    $criteria->compare('id',$this->id);

    $criteria->compare('name',$this->name,true);


    return new CActiveDataProvider($this, array(

      'criteria'=>$criteria,

    ));

  }

}

Member Model


<?php


/**

 * This is the model class for table "{{member}}".

 *

 * The followings are the available columns in table '{{member}}':

 * @property integer $id

 * @property integer $group_id

 * @property string $firstname

 * @property string $lastname

 * @property integer $membersince

 */

class Member extends CActiveRecord

{

  /**

   * Returns the static model of the specified AR class.

   * @param string $className active record class name.

   * @return Member the static model class

   */

  public static function model($className=__CLASS__)

  {

    return parent::model($className);

  }


  /**

   * @return string the associated database table name

   */

  public function tableName()

  {

    return '{{member}}';

  }


  /**

   * @return array validation rules for model attributes.

   */

  public function rules()

  {

    // NOTE: you should only define rules for those attributes that

    // will receive user inputs.

    return array(

      array('group_id, membersince', 'numerical', 'integerOnly'=>true),

      array('firstname, lastname', 'length', 'max'=>80),

      // The following rule is used by search().

      // Please remove those attributes that should not be searched.

      array('id, group_id, firstname, lastname, membersince', 'safe', 'on'=>'search'),

    );

  }


  /**

   * @return array relational rules.

   */

  public function relations()

  {

    // NOTE: you may need to adjust the relation name and the related

    // class name for the relations automatically generated below.

    return array(

      'group' => array(self::BELONGS_TO, 'Group', 'group_id'),

    );

  }


  /**

   * @return array customized attribute labels (name=>label)

   */

  public function attributeLabels()

  {

    return array(

      'id' => 'ID',

      'group_id' => 'Group',

      'firstname' => 'Firstname',

      'lastname' => 'Lastname',

      'membersince' => 'Membersince',

    );

  }


  /**

   * Retrieves a list of models based on the current search/filter conditions.

   * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.

   */

  public function search()

  {

    // Warning: Please modify the following code to remove attributes that

    // should not be searched.


    $criteria=new CDbCriteria;


    $criteria->compare('id',$this->id);

    $criteria->compare('group_id',$this->group_id);

    $criteria->compare('firstname',$this->firstname,true);

    $criteria->compare('lastname',$this->lastname,true);

    $criteria->compare('membersince',$this->membersince);


    return new CActiveDataProvider($this, array(

      'criteria'=>$criteria,

    ));

  }

}

Code for controller

Group controller




<?php


class GroupController extends Controller

{

  /**

   * @var string the default layout for the views. Defaults to '//layouts/column2', meaning

   * using two-column layout. See 'protected/views/layouts/column2.php'.

   */

  public $layout='//layouts/column2';


  /**

   * @return array action filters

   */

  public function filters()

  {

    return array(

      'accessControl', // perform access control for CRUD operations

    );

  }


  /**

   * Specifies the access control rules.

   * This method is used by the 'accessControl' filter.

   * @return array access control rules

   */

  public function accessRules()

  {

    return array(

      array('allow',  // allow all users to perform 'index' and 'view' actions

        'actions'=>array('index','view'),

        'users'=>array('*'),

      ),

      array('allow', // allow authenticated user to perform 'create' and 'update' actions

        'actions'=>array('create','update'),

        'users'=>array('@'),

      ),

      array('allow', // allow admin user to perform 'admin' and 'delete' actions

        'actions'=>array('admin','delete'),

        'users'=>array('admin'),

      ),

      array('deny',  // deny all users

        'users'=>array('*'),

      ),

    );

  }


  /**

   * Displays a particular model.

   * @param integer $id the ID of the model to be displayed

   */

  public function actionView($id)

  {

    $this->render('view',array(

      'model'=>$this->loadModel($id),

    ));

  }


  /**

   * Creates a new model.

   * If creation is successful, the browser will be redirected to the 'view' page.

   */

  public function actionCreate()

  {

    $model=new Group;

    $member=new Member;


    // Uncomment the following line if AJAX validation is needed

    // $this->performAjaxValidation($model);


    if(isset($_POST['Group'],$_POST['Member']))

    {

      $model->attributes=$_POST['Group'];

      $member->attributes=$_POST['Member'];

      if($model->save() & $member->save())

        $this->redirect(array('view','id'=>$model->id));

    }


    $this->render('create',array(

      'model'=>$model,

      'member'=>$member,

    ));

  }


  /**

   * Updates a particular model.

   * If update is successful, the browser will be redirected to the 'view' page.

   * @param integer $id the ID of the model to be updated

   */

  public function actionUpdate($id)

  {

    $model=$this->loadModel($id);


    // Uncomment the following line if AJAX validation is needed

    // $this->performAjaxValidation($model);


    if(isset($_POST['Group']))

    {

      $model->attributes=$_POST['Group'];

      if($model->save())

        $this->redirect(array('view','id'=>$model->id));

    }


    $this->render('update',array(

      'model'=>$model,

    ));

  }


  /**

   * Deletes a particular model.

   * If deletion is successful, the browser will be redirected to the 'admin' page.

   * @param integer $id the ID of the model to be deleted

   */

  public function actionDelete($id)

  {

    if(Yii::app()->request->isPostRequest)

    {

      // we only allow deletion via POST request

      $this->loadModel($id)->delete();


      // if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser

      if(!isset($_GET['ajax']))

        $this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('admin'));

    }

    else

      throw new CHttpException(400,'Invalid request. Please do not repeat this request again.');

  }


  /**

   * Lists all models.

   */

  public function actionIndex()

  {

    $dataProvider=new CActiveDataProvider('Group');

    $this->render('index',array(

      'dataProvider'=>$dataProvider,

    ));

  }


  /**

   * Manages all models.

   */

  public function actionAdmin()

  {

    $model=new Group('search');

    $model->unsetAttributes();  // clear any default values

    if(isset($_GET['Group']))

      $model->attributes=$_GET['Group'];


    $this->render('admin',array(

      'model'=>$model,

    ));

  }


  /**

   * Returns the data model based on the primary key given in the GET variable.

   * If the data model is not found, an HTTP exception will be raised.

   * @param integer the ID of the model to be loaded

   */

  public function loadModel($id)

  {

    $model=Group::model()->findByPk($id);

    if($model===null)

      throw new CHttpException(404,'The requested page does not exist.');

    return $model;

  }


  /**

   * Performs the AJAX validation.

   * @param CModel the model to be validated

   */

  protected function performAjaxValidation($model)

  {

    if(isset($_POST['ajax']) && $_POST['ajax']==='group-form')

    {

      echo CActiveForm::validate($model);

      Yii::app()->end();

    }

  }

}

As well the view file for Group _form.php file where I am rendering both models

<div class="form">


<?php $form=$this->beginWidget('CActiveForm', array(

  'id'=>'group-form',

  'enableAjaxValidation'=>false,

)); ?>


  <p class="note">Fields with <span class="required">*</span> are required.</p>


  <?php echo $form->errorSummary($model); ?>


  <div class="row">

    <?php echo $form->labelEx($model,'name'); ?>

    <?php echo $form->textField($model,'name',array('size'=>60,'maxlength'=>80)); ?>

    <?php echo $form->error($model,'name'); ?>

  </div>


  <div class="row">

    <?php echo $form->labelEx($member,'firstname'); ?>

    <?php echo $form->textField($member,'firstname',array('size'=>60,'maxlength'=>80)); ?>

    <?php echo $form->error($member,'firstname'); ?>

  </div>


  <div class="row">

    <?php echo $form->labelEx($member,'lastname'); ?>

    <?php echo $form->textField($member,'lastname',array('size'=>60,'maxlength'=>80)); ?>

    <?php echo $form->error($member,'lastname'); ?>

  </div>


  <div class="row">

    <?php echo $form->labelEx($member,'membersince'); ?>

    <?php echo $form->textField($member,'membersince'); ?>

    <?php echo $form->error($member,'membersince'); ?>

  </div>


  <div class="row buttons">

    <?php echo CHtml::submitButton($model->isNewRecord ? 'Create' : 'Save'); ?>

  </div>


<?php $this->endWidget(); ?>


</div><!-- form -->



Note:I have used render_partial for both models in group create.php

<?php echo $this->renderPartial('_form', array('model'=>$model,'member'=>$member)); ?>

A member does not automatically know that it is part of a group. You must manually populate the foreign key to link the member to the group.

You can do this in the actionCreate() method as shown below.




public function actionCreate()

{

  $model=new Group;

  $member=new Member;


  // Uncomment the following line if AJAX validation is needed

  // $this->performAjaxValidation($model);


  if(isset($_POST['Group'],$_POST['Member']))

  {

    $model->attributes=$_POST['Group'];

    if($model->save())

    {

      $member->attributes=$_POST['Member'];

      /* Right now $member->group_id is not populated.  $model->id was populated with the calculated id

       * (assuming id is auto incremented) when we ran $model->save().  Now we populate group_id with this

       * id to link this member to that group.

       */

      $member->group_id = $model->id;

      if($member->save())

      {

        $this->redirect(array('view','id'=>$model->id));

      }

    }

  }

  $this->render('create',array(

        'model'=>$model,

        'member'=>$member,

  )); 

}



As a side note: I recommend renaming id to group_id in the group table. Having inconsistent column names can be tricky when you add more tables and foreign keys. In the same spirit, I recommend you rename id to member_id in the member table.

Thank you @ Steven89 it really helped me.

Now can you tell me when I am goint to save the form for both models whuch has been made rendered in a single form after clicking the attributes for the first model can be seen after save.So how to render the both models attributes view even after clicking save button?

I’m not sure I completely understand what your getting at.

But you can now access groups from members and members from groups.

I think the code below will allow you to do that:




/* Group that member 1 belongs to */

$member = Member::model()->findByPk(1);

$group = $member->group


/* Members of group 1 */

$group = Group::model()->findByPk(1);

$members = $group->member;



$member = Member::model()->findByPk(1);

$group = $member->group

Thank you for your help. Ya this one is working but it is showing only with id 1 which one has been given in that findByPk(1)

To get the id’s we can use this line


$model=$this->loadModel($id);

    $member = Member::model()->findByAttributes(array('group_id'=>$_GET['id']));