$data vs other variables in views

Hi all,

I’m new to yii and working on my first project in parallel to all the tutorials (that’s how I learn). Here’s a question for you:

I have two tables, department and employee where department is in a HAS_MANY relationship to employee (and of course, therefore, employee is in a BELONGS_TO relationship to department). The PK for department is department_id. The PK for employee is employee_id and the FK department_id (department 1—>n employee).

What I want to have happen is for the department view/index to look something like this:

That is to say, I’d like all the relevant department information, followed in each case by a listing of all the employees.

Following the example here, I’ve managed to get what I want using something like this in the department _view view




<?php

//$models = Department::model()->findAll();  // lazy loading

$models = Department::model()->with('employees')->findAll(); // eager loading


foreach ($models as $model) : ?>

<div class="view">


  <p>Department ID: <?php echo $model->department_id ?></p>

  <p>Department Name: <?php echo $model->name ?></p>

  <p>Location: <?php echo $model->location ?></p>

  <p>Fax: <?php echo $model->fax ?></p>

  <p>Employees: <?php foreach ($model->employees as $employee) {

    echo $employee->employee_id .'</p>';

    }?>

</div>

<?php endforeach ?>



The problem (or the less elegant part of this) is that this method means I seem to be ignoring the more elegant original system in the (automatically generated) _view view:




<div class="view">


	<b><?php echo CHtml::encode($data->getAttributeLabel('department_id')); ?>:</b>

	<?php echo CHtml::link(CHtml::encode($data->department_id), array('view', 'id'=>$data->department_id)); ?>

	<br />


	<b><?php echo CHtml::encode($data->getAttributeLabel('name')); ?>:</b>

	<?php echo CHtml::encode($data->name); ?>

	<br />


	<b><?php echo CHtml::encode($data->getAttributeLabel('location')); ?>:</b>

	<?php echo CHtml::encode($data->location); ?>

	<br />


....



My questions:

  1. Is there a way of somehow inserting the HAS_MANY relation into this $data object so that I don’t need to recode everything and can keep the getAttributeLabel method (and extend it to the relational data from employee)?

  2. Is _view really the right place to put the foreach that is getting the relational data for me? It seems to me it would make most sense as part of the department model (but I can’t see how to put it there) or ?maybe less sensibly in the department controller? I love the way BELONGS_TO relationships become attributes of the self:: model; I’m not seeing any way of doing that with the arrays produced by HAS_MANY.

  3. Can I get other relational data from the employee table this way? I.e. if I wanted to get "employee_lastName" or example, or "employee_lastName" and "employee_firstNames" where I now have the id

  4. If employee also had a BELONGS_TO relationship to a third table (let’s say bargaining_unit), what would I need to change in the above to do something like this, where the information in parenthesis is the bargaining unit):

Note: in this case, I’m assuming the following table relations: department 1—>n employee n<—1 bargaining_unit

I really appreciate all help and please let me know (and excuse and let me know) if I’m not doing things exactly the way this forum prefers

Hi,

  1. //controller

		$dataProvider=new CActiveDataProvider('Department', array(

            	'criteria'=>array(

                	'with'=>array('employees'),

         			)

            	));



// _view


<b><?php echo CHtml::encode($data->getAttributeLabel('location')); ?>:</b>

<?php foreach ($data->employees as $employee) {

    echo $employee->employee_id;

    }?>



  1. I don’t see anything wrong with foreach. You may put this pieace of code to Department::model()->findEmployees(), for example, as well.

In your code, it’s more natural for MVC to have


$models = Department::model()->with('employees')->findAll(); // eager loading

in your controller (I suppose it’s in a view just for the example simplicity)

  1. Of course.

$employee->employee_name

  1. You may put your second relation table to eager loading request as well.

$models = Department::model()->with('employees.bargain')->findAll(); // eager loading


		$dataProvider=new CActiveDataProvider('Department', array(

                                                          	'criteria'=>array(

                                                                   	'with'=>array('employees.bargain'),

                                                 	)            	

                                   	));

 

Thanks for a really clear set of answers! This is excellent for new people like me. I’ll try them out now.

Two followups:

  1. There’s one mistake in the code

That should be (I think)




$dataProvider=new CActiveDataProvider('Department', array(

                'criteria'=>array(

                        'with'=>array('employees.bargain'),

                        )

                ));



  1. For people like me who are still very new about this let me say:

[indent]a) you add these data provider instances in series in the controller (i.e. you don’t replace the original with a new one, you put the new one in beside the default (although the example of controller code in 1 /can/ be replaced by that in 4)[/indent]

[indent]B) for controller code (4), you use something like the following in your _view in order to extract the text: [/indent]




<b><?php echo CHtml::encode($data->getAttributeLabel('Employees/Bargaining Unit')); ?>:</b>

        <?php foreach ($data->employees as $employee) {

            echo $employee->name . '/' . $employee->bargain->name;

            }?>



Yes, thank you, there was a typo. The dataProvider should be the same, like it’s written the first time.