Cakephp - contain (containable behavior) fetches too much - php

As I understood from the cakephp-documentation, one of the advantages of the 'containable'-Behavior is being able to fetch fewer data if you need fewer data...
But that doesn't seem to work in my case of a connection between users and usergroups.
My associations look like:
Group
hasMany: Membership
User
hasMany: Membership
Membership
belongsTo: User, Group
(I'm not using HABTM, instead use the Model 'Membership' in between to join users and groups).
All Models implement the 'Containable'-Behavior.
Now I want to get all the members of a group with a certain id, only their ids and mail-addresses. My query is built like that:
$members = $this->Membership->find('all', array(
'conditions' => array(
'group_id' => $id
),
'contain' => array(
'User' => array(
'fields' => array('id', 'fullName')
),
)
));
But the resulting array looks like:
array(
(int) 0 => array(
'Membership' => array(
'id' => '1',
'group_id' => '1',
'user_id' => '1',
'role' => 'member'
),
'Group' => array(
'id' => '1',
'name' => 'Foo Group'
),
'User' => array(
'password' => '*****',
'id' => '1',
'name' => 'Dr. Foo'
'mail' => 'foo#bar.baz',
'role' => 'admin'
)
)
)
So there are definietely more fields fetched than I wanted to... (it's the same thing btw wenn I set the 'contain'-key to:
'contain' => array(
'User.fullName', 'User.id'
)
Am I using the containable-behavior wrong?

Your models don't seem to be acting containabl-y at all. Have you set your models to act as containable?
class Post extends AppModel {
public $actsAs = array('Containable');
}
If so, maybe the problem is with the recursion (to avoid getting the Group array with the query). Containable behavior should handle the recursion level on its own, but try setting it on the AppModel just to be sure
class AppModel extends Model {
public $actsAs = array('Containable');
public $recursive = -1;
Your first attempt
'contain' => array(
'User' => array(
'fields' => array('id', 'fullName')
),
)
looks good in terms of syntax, so it probably the actAs thing.
Also, for debugging also, try
$this->Membership->contain('User');
$this->Membership->find('all', array(
'conditions' => array(
'group_id' => $id
));
and see if you get the expected results that way.

Related

CakePHP - saveAssociated/saveAll behaves like saveMany

I have two Models, namely Product and ProductSpecification which have the following relations in place:
(Product Model)
public $hasMany = array(
'ProductSpecification' => array(
'className' => 'ProductSpecification',
'foreignKey' => 'product_id',
'dependent' => true
)
);
and
(ProductSpecification Model)
public $belongsTo = array(
'Product' => array(
'className' => 'Product',
'foreignKey' => 'product_id'
)
);
Using the CakePHP Form helper I post ProductSpecification data and then I use the saveAll method (or saveAssociated, I've tried both) to save the data. debug($this->request->data) gives me the following output after POSTing:
array(
'Product' => array(
'id' => '2'
),
'ProductSpecification' => array(
'title' => 'test',
'step' => '1',
'position' => '1'
)
)
This is great, right..? Now, the line after the debug I use the following code to save (I've also tried saveAssociated):
if($this->Product->saveAll($this->request->data))
For some odd reason this saves three(!) empty rows in my ProductSpecification table, with only the product_id field (and id) set; the fields title, step and position are empty. Exactly the same behavior happens when I run saveAssociated. What am I doing wrong?
I'm running CakePHP 2.x.
Your save data should look more like this:-
array(
'Product' => array(
'id' => '2'
),
'ProductSpecification' => array(
array(
'title' => 'test',
'step' => '1',
'position' => '1'
)
)
);
The values for ProductSpecification need to be passed as a numerically indexed array for the hasMany relationship.
Also, make sure you use saveAssociated() rather than saveAll() as you are passing associated data so there is no need to use the wrapper method (which should be avoided wherever possible).

Deep select accociated model data Cakephp 2.x

i have this model structure Client->Project->Landlord->Property
Property belongsto Landlord
Landlord belongsto Project
Project belongsto Client
inside the properties controller i want all the properties that belong to a specific client
How do i do this i have tried it with containable but it always gives me all Properties and not the ones that are related with their foreign keys.
$properties = $this->Property->find('all', array(
'contain' => array(
'Landlord' => array(
'Project' => array(
'conditions' => array(
'client_id' => $user['client_id'] // Passed parameter
)
),
'conditions' => array(
'Landlord.project_id' => 'Project.Id'
)
)
)
));
This isn't doing anything, it evens seems to ignore any typo's i made. what am i doing wrong here?
Oke i figured it out with joins this is what i came up with.
$joins = array(
array('table'=>'projects',
'alias' => 'Project',
'type'=>'inner',
'conditions'=> array(
'Project.client_id = '.$user['client_id']
)),
array('table'=>'landlords',
'alias' => 'Landlord',
'type'=>'inner',
'conditions'=> array(
'Project.id = Landlord.project_id','Landlord.id = Property.landlord_id'
)),
);
$properties = $this->Property->find('all',array('joins'=>$joins,'recursive'=>-1));

CakePHP getting data form an ID which is inside another table?

Right, so my data returns in the following way,
(int) 0 => array(
'MODEL-XX' => array(
//DATA HERE
'xxs_id' => '11',
'aas_id' => '44',
'vvs_id' => '2'
),
'xxs' => array(
'id' => '11',
'customername' => 'XX name here'
),
'aas' => array(
'id' => '44',
'clientname' => 'aa name here',
'xxs_id' => '11'
),
'vvs' => array(
'id' => '2',
'start' => '1405296000',
'end' => '1405814400',
'users_id' => '1'
)
This works fine, but I want to know how to link my users table to this model. So the details of each user for my VV model would become apart of the data. My MODEL-XX does not have any links with my users table so the place I need to call in the users details are held with my VV model.
I have been looking into this but have not been able to find a simple easy method for doing this?
I was thinking that this would be doable with my model, so I opened my my XX model and added the following within my '$belongsTo' section,
'Users' => array(
'className' => 'Users',
'foreignKey' => 'vvs.users_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
So is there a easy method for linking data like this?
Please give me time, if I have not explained myself right or not enough data, please tell me and let me fix or explain better.
Thanks,
Either set your recusive higher:
$this->MODEL-XX->recursive = 1; //or 2
Or and this should be your prefered way to go, start using the containable behaviour:
http://book.cakephp.org/2.0/en/core-libraries/behaviors/containable.html
In your appModel:
public $actsAs = array('Containable');
Then try this find:
$this->MODEL-XX->recursive = -1;
$data = $this-MODEL-XX>find(
'all', array(
'conditions' => $conditions,
'contain' => array('xxs', 'aas', 'vvs', 'user')
)
);
I might be 'vvs.user' but I forgot what is used for deeper models

Display a field from a 3rd table

I am trying to display a field from a 3rd table in a relationship, and after checking posts here and the docs, I am still stuck.I have 3 models all related in some way. I have found similar posts here but I am still not getting it to work. I am learning so sorry if I have missed this somewhere in the docs but I have read a fair bit and have tried a lot. I am guessing too much now on this so I need help.
1)Tutorsession - belongsto teachers,
2) Teacher -has 1 user,hasmany tutorsessions
3) User- has 1 teacher, //////I want to display a field from this table given I display tutorsessions
In controller
$this->set('tutor',
$this->Tutorsession->find('first',
array(
'conditions' => array('Teacher.user_id' => $id),
'contain' => 'User.username'
)
)
); //////////no error but no results
from view echo '<td>'. $item['User']['username'].'</td>'; ///////error user undefined
The tutorsession automatically gets rows from teacher table but not user table witht he model setup on a findall.
I want to display a username from the user table. I display the tutorsession table , I then can display the teacher table with the model association but I cant go from the teacher table to the user table to get a user name from the user id as the common field. I have checked the docs below and I am not sure why my code isnt ble to display a username from users table.
http://book.cakephp.org/2.0/en/core-libraries/behaviors/containable.html
http://book.cakephp.org/2.0/en/models/retrieving-your-data.html
update: here are the models
class User extends AppModel {
public $hasOne = array(
'Teacher' => array(
'className' => 'Teacher',
'dependent' => true
)
class Tutorsession extends AppModel
{
public $name='Tutorsession';
public $belongsTo = array(
'Teacher' => array(
'className' => 'Teacher',
'foreignKey' => 'teacher_id'
)
class Teacher extends AppModel
{
public $name='Teacher';
public $hasMany = array('Tutorsession');
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id'
)
);
Add containable behavior in your Model
public $actsAs = array('Containable');
Execute following query In controller
$contain = array('Teacher' => array('User'));
$this->set('tutor', $this->Tutorsession->find('first',array(
'conditions' => array('Teacher.user_id' => $id),
'contain' => $contain
)));
Try this:
$this->Tutorsession->recursive = 2;
$this->Tutorsession->Teacher->contain('User');
$this->set('tutor',
$this->Tutorsession->find('first',
array(
'conditions' => array('Teacher.user_id' => $id)
)
)
);
$tutor=$this->Teacher->find('first',
array(
'conditions' => array('Teacher.user_id' => $id)
)
);
debug($tutor); exit();
Your result similar:
'Teacher' => array(
'id' => '1',
'name' => 'abc',
'created' => '1397040385',
'updated' => '1397725860'
),
'User' => array(
'id' => '4',
'name' => 'administrators',
'created' => '1397032953',
'modified' => '1397032953'
),
'Tutorsession' => array(
0=>array(
'id' => '3',
'name'=>'abc',
'created' => '1400729137'
),
1=>array(
'id' => '4',
'name'=>'abc',
'created' => '1400729137'
)
)
Ensure your models are correct

CakePHP retrieve data, associate models, containable behavior

I can't seem to figure out how the containable behavior works, or how to retrieve the data from (and based) on associated models.
I need to put the following MySQL query in the cakephp find('all') function, I know i can use the query builder for the sql syntax but I want to use find function and want to figure out how it works.
SELECT events.id, events.name FROM events, user_roles
WHERE user_roles.event_id = events.id
AND user_roles.user_id = 1
The idea is simple, in the user_roles the user_id, role_id and event_id are stored. Now I want to retrieve all events for a certain user (here user_id = 1). I tried some variations on the following:
$data = $this->Event->find('all',array(
'contain' => array(
'UserRole' => array(
'fields' => array('id'),
'conditions' => array(
'UserRole.user_id' => $this->Auth->user('id')
)
)
)
));
But this keeps returning all events. What I want is an array like (or any other result with the same associated data):
array(
[0] => array(
[Event] => array(
'id' => 1,
'name' => 'Event Name'
),
[UserRole] => array(
'role_id' => 2,
'event_id'=> 1
)
[1] => array(
.... etc ...
)
The following models and associations are defined
class Event extends AppModel {
public $hasMany = array(
'UserRole' => array(
'className' => 'UserRole',
'foreignKey' => 'event_id',
'dependent' => false,
)
)
)
class UserRole extends AppModel {
public $belongsTo = array(
'Event' => array(
'className' => 'Event',
'foreignKey' => 'event_id'
),
)
)
So how does it work ;).
Edit:
I forgot to mention that I've set in AppModel.php:
public $recursive = -1;
Containable finds the associated records for the original query. What you are doing is a find('all') on your Event model with absolutely no conditions, so it will return all Events.
Then Containable will retrieve all the UserRole records that are for the given user_id and are also associated to the Event by the event_id
If you want to only retrieve events for the given user, you could do it one of two ways
Via the Event->UserRole association and chained models:
$data = $this->Event->UserRole->find('first', array(
'conditions' => array('UserRole.user_id' => $this->Auth->user('id'),
'contain' => array('Event')
));
$events = $data['Event'];
or
Via your current code and then using the Hash::extract method to get the Events that match. (Hash is a CakePHP core class)
$events = Hash::extract('/UserRole[user_id='.$this->Auth->user('id').']/..', $data);

Categories