I'm currently new to Yii and have some problems in my app.
I have 2 AR (Employee and Children) with the relations is Employee has_many Children. Now when we go into the view of Employee (in the view&id=blablabla not in index), I want to list all the children that the Employee have.
I have made a function in EmployeeController class to retrieve the children from my db
$anak = Anak::Model()->findAll(array(
'condition'=>'id_karyawan=:id_karyawan',
'params'=>array(':id_karyawan'=>$id_karyawan)));
//return $anak;
foreach ($anak as $data){
return $data->namaanak;
}
the problem is, it only showing 1 data (the first one, to be exact) of the children, even though in my db the Employee has 3 children. When I try to count of query result, it's showing 3.
My employee/view is like this
$this->widget('zii.widgets.CDetailView', array(
'data'=>$model,
'attributes'=>array(
'id_karyawan',
'nama',
array(
'name'=>'idjabatan',
'value'=>$model->findByPk($model->id_karyawan)->jabatan->namajabatan,
),
array(
'name'=>'gaji',
'value'=>Yii::app()->numberFormatter->formatCurrency($model->findByPk($model->id_karyawan)->jabatan->gaji, 'Rp'),
),
'alamat',
array(
'name'=>'ttl',
'value'=>$model->tempatlahir.', '.Yii::app()->dateFormatter->format("dd MMMM yyyy", $model->tgllahir),
),
array(
'name'=>'Istri',
'value'=>Istri::model()->getNama($model->id_karyawan),
'type'=>'raw'
),
array(
'name'=>'Anak',
'value'=>$this->getAnak($model->id_karyawan),
'type'=>'raw'
)
),
I have tried to google it, but i couldn't find any working answer :(
PS: karyawan = employee, anak = children.
You are only getting the first related value because you are returning it right away inside your foreach loop in the function. Gather all the related models first then return that and work with that data.
You can also skip that extra function inside your controller. If you use Gii, it should have already set up the proper Employee HAS_MANY children relation for you, so you could use that to pull all related models for each Employee model you are looking at. See below for a quick example
Employee model:
public function relations()
{
return array(
'children' => array(self::HAS_MANY, 'Child', 'employee_id'),
);
}
View file, passing an employee model to CDetailView:
$this->widget('zii.widgets.CDetailView', array(
'data' => $model,
'attributes'=>array(
array(
'name' => 'Children',
'value' => function ($data) {
// Get all related children using the relation defined in the Employee model and use CHtml::listData to store data inside the $children variable as an array using `id` as key and `child_name` as value
$children = CHtml::listData($data->children, 'id', 'child_name');
// Return names as a comma separated list
return implode(', ', $children);
},
'type'=>'raw'
)
)
);
My tables/column names probably don't match up with what you have but hopefully this helps.
Related
I'm getting foreign key relation based display ids in the gridviews. How to get values instead of ids? Code in my gridview is following:
$criteria->compare('education.UniversityNameid',$this->UniversityName, true);
my gridviews inside code
array(
'name' => 'UniversityName',
'type' => 'raw',
'value'=>'(empty($data->education->UniversityNameid))? "" : Yii::app()->params["currencySymbol"]." ".$data->education->UniversityNameid',
),
You have to set up a relation in your model "University" like this
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(
'UniversityName' => array(self::BELONGS_TO, 'University', 'UniversityNameid'),
);
}
thank you can access the Name
$data->education->UniversityName
Set the relation in your model like
'u' => array(self::BELONGS_TO, 'University', 'UniversityNameid'),
and acess it like
'attributes'=>array(
array('name'=>'u.UniversityName',
'label'=>'University',),
),
We have two models which are related by a has and belongs to many (HABTM) relationship: Jobs, Tests. We are able to add/edit the relationships successfully (we know because they show up in the join table), but their created and modified fields are never set.
Here are the model relationships:
//Job.php
public $hasAndBelongsToMany = array (
'Test' => array (
'classname' => 'Test',
'foreignKey'=>'job_id',
'joinTable' => 'jobs_tests',
'associatedForeignKey' => 'test_id'
)
);
//Test.php
public $hasAndBelongsToMany = array(
'Job' => array(
'className'=> 'Job',
'joinTable'=>'jobs_tests',
'foreignKey' => 'test_id',
'associatedForeignKey'=> 'job_id'
)
);
Here is the /view/Jobs/edit.ctp
echo $this->Form->select('Test', $test_options, array('class'=>'form-control', 'multiple'=>'checkbox'));
//This is always empty (nothing selected/checked).
Here is how we update in the controller...
if ($this->request->isPut() ) {
$data = $this->request->data;
$save = $this->Job->save( $data );
if ($save) {
$this->Session->setFlash('Job edited');
} else {
$this->Session->setFlash('Error editing job');
}
}
The records in the join table are correct but created and modified are always NULL.
What are we doing wrong?
I dont't think that cake fills created and modified even in HABTM join table. (I tried in one project of mine and it didn't work too but maybe it can be activated somwhow)
However if you don't set unique to true in your association array the records are deleted and re-created on every update, so the update field has no meaning here.
If you really want the two fields then you have to use the Has Many Trough relationship.
I have 2 tables namely Equipment and Supply.
I have used array_merge in yii php to serve as union for two different tables for the purpose of diplaying them in a single grid.
Everything works fine with the fields that is common with the two tables. The problem is when I try to display a field that is only existing in one of these two tables. It says Property "Supply.equipType" is not defined" because only equipment has the equipType relation.
in my gridView:
array(
'name'=>'equipment_type',
'value'=>'$data->equipType->name',
),
in my controller where I did the merging:
$prov1 = new CActiveDataProvider('BaseEiEquipItem', array(
'criteria' => array(
'condition' => 'id>0'
)));
$prov2 = new CActiveDataProvider('BaseSiReceivedItem', array(
'criteria' => array(
'condition' => 'id>0'
)));
$records=array_merge($prov1->data , $prov2->data);
$provAll = new CArrayDataProvider($records,
array(
'sort' => array( //optional and sortring
'keyField'=>false,
'attributes' => array(
'id', 'description',),
),
'pagination' => array('pageSize' => 10) //optional add a pagination
)
);
$this->render('create',array(
'model'=>$model,
'searchModel'=>$searchModel,
'modelGrid'=>$modelGrid,
'provAll' => $provAll,
));
in my equipment model :
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(
'equipType' => array(self::BELONGS_TO, 'BaseRefEquipmentType', 'equipment_type'),
);
}
Any idea on how to solve this? Is there any way to fake a relation or something?
thanks in advance
Just add condition to check if equipType is there:
'value'=>'isset($data->equipType) ? $data->equipType->name : ""'
Using sql to merge results would be better, though.
Can't you just use plain SQL union?
If Equipment has 2 fields (a, b) and Supply has 2 fields (b, c), you can do union like this:
SELECT a, b, null FROM Equipment
UNION ALL
SELECT null, b, c FROM Supply
This problem shows, that it's probably not a good idea to mix different model types in one gridview. If you have a model that has no equipType then it's pretty obvious, that you can't show this column in a gridview. So what would you expect?
As a (dirty) workaround you can add all missing columns as pseudo attributes to the models where they are missing:
public $equipType;
This is driving me nuts. I read many responses and tutorials and i can't pin point the problem here.
I have 2 Tables: tblEmpleado and tblProfesion Here is an image of the MySQL relations they have (Marked on red)
I want to display on a CGridView the attribute "Descripcion" from the table tblProfesion when displaying the data from tblEmpleado.
I tried using claveProfesion.descripcion without avail (It shows the INT number of the FK just fine without the ".descripcion" part). Also tried using something like:
array(
'header'=>'tableHeaderName',
'value'=>'(isset($data->claveProfesion)) ? $data->claveProfesion->descripcion : null', )
getting "Trying to get property of non-object".
Here is the Empleados.php relation part of the model code:
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(
'tblcelulars' => array(self::HAS_MANY, 'Tblcelular', 'claveEmpleado'),
'tblcuentabancos' => array(self::HAS_MANY, 'Tblcuentabanco', 'claveEmpleado'),
'idCentroTrabajo' => array(self::BELONGS_TO, 'Tblcentrotrabajo', 'idCentroTrabajo'),
'convenio' => array(self::BELONGS_TO, 'Tblconvenio', 'convenio'),
'claveProfesion' => array(self::BELONGS_TO, 'Tblprofesion', 'claveProfesion'),
);
}
And the CGridView part of the Admin.php View code
<?php $this->widget('zii.widgets.grid.CGridView', array(
'id'=>'empleados-grid',
'dataProvider'=>$model->search(),
'filter'=>$model,
'columns'=>array(
'claveEmpleado',
'nombreEmpleado',
'idCentroTrabajo',
array(
'header'=>'tableHeaderName',
'value'=>'($data->claveProfesion!=null) ? $data->claveProfesion->descripcion : null',
),
'aniosExperiencia',
'telefono2',
'email',
...
array(
'class'=>'CButtonColumn',
),
),
)); ?>
And last, i don't know if its related but in the Model class "Profesiones.php" the relation is as follow:
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(
'tblempleados' => array(self::HAS_MANY, 'Tblempleado', 'claveProfesion'),
);
}
Could anyone help me out with this?
Your column and your relation both have the same name claveProfesion. As such Yii is returning the column instead of the relation when you call claveProfesion. To resolve it rename your relation to something else e.g claveProfesionObject
public function relations()
{
return array(
...
'claveProfesionObject' => array(self::BELONGS_TO, 'Tblprofesion', 'claveProfesion'),
);
}
Is it possible to access more than one model deep in a relationship in Lithium?
For example, I have a User model:
class Users extends \lithium\data\Model {
public $validates = array();
public $belongsTo = array("City");
}
and I have a City model:
class Cities extends \lithium\data\Model {
public $validates = array();
public $belongsTo = array("State");
}
and a State model, and so on.
If I'm querying for a User, with something similar to Users::first(), is it possible to get all the relationships included with the results? I know I can do Users::first(array('with' => 'City')) but I'd like to have each City return its State model, too, so I can access it like this:
$user->city->state->field
Right now I can only get it to go one deep ($user->city) and I'd have to requery again, which seems inefficient.
Using a recent master you can use the following nested notation:
Users::all( array(
'with' => array(
'Cities.States'
)
));
It will do the JOINs for you.
I am guessing you are using SQL?
Lithium is mainly designed for noSQL db´s, so recursiveness / multi joins are not a design goal.
You could set up a native sql join query and cast it on a model.
query the city with Users and State as joins.
you could setup a db based join view and li3 is using it as a seperate model.
you probably should split your planned recursive call into more than one db requests.
Think about the quotient of n Cities to m States. => fetch the user with city and then the state by the state id. => pass that as two keys or embed the state info. This would be acceptable for Users::all() queries aswell.
Example using Lithiums util\Set Class:
use \lithium\util\Set;
$users = Users::all(..conditions..);
$state_ids = array_flip(array_flip(Set::extract($users->data(), '/city/state_id')));
$stateList = States::find('list',array(
'conditions' => array(
'id' => $state_ids
),
));
You can set up relationships in this way, but you have to use a more verbose relationship definition. Have a look at the data that gets passed when constructing a Relationship for details about the options you can use.
class Users extends \lithium\data\Model {
public $belongsTo = array(
"Cities" => array(
"to" => "app\models\Cities",
"key" => "city_id",
),
"States" => array(
"from" => "app\models\Cities",
"to" => "app\models\States",
"key" => array(
"state_id" => "id", // field in "from" model => field in "to" model
),
),
);
}
class Cities extends \lithium\data\Model {
public $belongsTo = array(
"States" => array(
"to" => "app\models\States",
"key" => "state_id",
),
);
}
class States extends \lithium\data\Model {
protected $_meta = array(
'key' => 'id', // notice that this matches the value
// in the key in the Users.States relationship
);
}
When using the States relationship on Users, be sure to always include the Cities relationship in the same query. For example:
Users::all( array(
'with' => array(
'Cities',
'States'
)
) );
I have never tried this using belongsTo relationships, but I have it working using hasMany relationships in the same way.