Many To Many Relationship With Same Model


(Prashu132) #1

Hi,

  I'm a newbie in Yii framework. I just got stuck in a relationship problem please help me to solve it. Problem is described below.





  Relationship is actually with the same model. I have an [b]Employee[/b] model. Usually a company will have only one manager per employee. But in this case there may be more than one manager per employee. He also will be another [b]Employee[/b] only who may or may not have one or more managers again. 





  So I need to define [b]Many-to-Many[/b] relationship for [b]Employee[/b] model with itself. How can I achieve that. I googled a lot, but didn't find any proper solution. 





  Hope you understand the problem. Please help me ASAP. 





 Thank you


     Prashanth

(Softark) #2

Hi Prashanth,




person

  id

  name


employee_manager

  employee_id ... FK to person.id

  manager_id  ... FK to person.id


// Person.php

'managers'  => array(self::MANY_MANY, 'Person', 'employee_manager(employee_id, manager_id)'),

'employees' => array(self::MANY_MANY, 'Person', 'employee_manager(manager_id, employee_id)'),



I changed ‘Employee’ to ‘Person’ in order to clarify the wording, because employee can have many employees.

The point is that you can create a bridge table that defines the relations between 2 persons: one is employee and the other is manager. And the Person model has 2 relations: employees and managers.

By doing this you can retrieve the managers and the employees of one person.




$person = Person::model()->findByPk($id);

foreach($person->managers as $manager)

    echo $person->name . " has manager named " . $manager->name . "\n";

foreach($person->employees as $employee)

    echo $person->name . " has employee named " . $employee->name . "\n";




(Prashu132) #3

Hi softark,

 Below given is my implementation. Can you please check it and confirm.



employee

  id

  name

....


subordinate_manager

  subordinate_id

  manager_id


// Employee.php

'managers' => array(self::MANY_MANY, 'Employee', 'subordinate_manager(subordinate_id, manager_id)'),

'subordinates' => array(self::MANY_MANY, 'Employee', 'subordinate_manager(manager_id, subordinate_id)')



With this situation, I was trying to create a new employee where multi select dropdownlist provides option to select managers. in actionCreate i am trying to save the employee with following code (i am using CAdvancedArBehavior extension) and





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

$model->managers = Employee::model()->findAll("`Id` IN ('" . implode("','", $_POST['Employee']['managers']) . "')");


if($model->save())

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



that creates an error




Property "Employee.manager_id" is not defined.




(Softark) #4

I’m sorry, I’m not familiar with that extension and can not help you on it.

But according to the following comment which is on the extension’s page, it has a bug in saving MANY_MANY relation.

http://www.yiiframework.com/extension/cadvancedarbehavior#c6548

The comment was posted on 2012/01/17, and the extension was uploaded on 2011/5/25. So I think the bug is still there.


(Prashu132) #5

Thanks dude. Can you give me a sample code to save a Employee record along with the relationship manually without that extension.


(Softark) #6

Well, it’s boring simple.

  1. Create a CActiveRecord class for subordinate_manager.

  2. Manually set employee_id and manager_id to an instance of SubordinateManager objects and save.




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

if($model->save())

{

    foreach($_POST['Employee']['managers'] as $manager_id)

    {

         $link = new SubordinateManager();

         $link->subordinate_id = $model->id;

         $link->manager_id = $manager_id;

         $link->save();

    }

}




(Prashu132) #7

It needs an extra class for SubordinateManager. And my problem is fixed within the bug report (the link you gave) the reported guy has given its fix too. I applied the fix and now its perfectly fine. subordinate_manager entries are automatically added when i add the following line before saving the Employee object.


$model->managers = Employee::model()->findAll("`Id` IN ('" . implode("','", $_POST['Employee']['managers']) . "')");


(Prashu132) #8

I have copied the fix given by the bug reporter so that it may be useful for someone in future.