Link the same model twice to another model in CakePhp - php

It's probably a very basic problem, but I can't wrap my head around it how to solve this properly.
In my application, I've got users who have multiple addresses with different purposes. For example, a user can have an Address and an InvoiceAddress. I want to store both addresses in the same table (the Address model) and then assign them to one User.
The respective models look something like:
Address:
public $belongsTo = array(
'Address' => array(
'className' => 'Address',
),
'InvoiceAddress' => array(
'className' => 'Address',
),
);
And the User:
public $hasOne = array(
'Address' => array(
'className' => 'Address',
),
'InvoiceAddress' => array(
'className' => 'Address',
),
);
When a user would have one address, I'd add a user_id as foreign key to the Address model and be done with it. But obviously, something has to be done differently for CakePhp to be able to distinguish between the address and the invoice address.
In my mind the solution is something like adding a address_id and invoice_address_id to the User table, but I can't seem to get it working in any way.

If you want to add in your user table the related fields then it is better to add them in the following form address_user_id and the invoice_address_user_id. Then you must have a belongsTo relation in your user model that looks like:
public $belongsTo = array(
'Address' => array(
'className' => 'Address',
'foreignKey' => 'address_user_id',
),
'InvoiceAddress' => array(
'className' => 'Address',
'foreignKey' => 'invoice_address_user_id',
),
);
So when you execute the following command $this->User->find('all'); the result will be
$result = array(0 =>
array('User' => array(...),
'Address' => array(...), // it will bring only one address row
'InvoiceAddress' => array(...) // it will bring only one address row
),
1 => ...
2 => ...
);
Then in your address Model the relationships you must add are:
public $hasOne = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'address_user_id',
),
'InvoiceUser' => array(
'className' => 'User',
'foreignKey' => 'invoice_address_user_id',
)
);

Related

Delete record from multiple tables when using a View CakePHP 2.8.x

I am using CakePHP 2.8.x and i'm looking for a way to delete records from 2 tables with 1 delete action.
I created a View from 3 tables: visitors, guests and registrations. These tables are connected through visitor_id.
In the Visitor Model i added the View in $useTable. Now when i press delete on, for example, visitor 1, i want to delete the records from visitor 1's guests and registrations tables and keep the visitor information in the visitor's table
I did found $this->Visitor->delete($id), but what parameters do i need to add to this function, so i can delete just the records from the guests and registrations tables?
If i need to give more information, i'm happy to help! Thx in advance
Update: The tables are associated. These are the models:
Visitor:
public $hasMany = array(
'Guest' => array(
'className' => 'Guest',
'foreignKey' => 'visitor_id',
'dependent' => false,
'exclusive' => false,
),
'Registration' => array(
'className' => Registration',
'foreignKey' => 'visitor_id',
'dependent' => false,
'exclusive' => false,
),
);
public $belongsTo = array(
);
Registration:
public $belongsTo = array(
'Visitor' => array(
'className' => 'Visitor',
'foreignKey' => 'visitor_id',
),
);
Guest:
public $belongsTo = array(
'Visitor' => array(
'className' => 'Visitor',
'foreignKey' => 'visitor_id',
),
there's the deleteAll() function in cake 2 (see the cookbook)
you have to pass to the function an array of conditions. In your case you want to delete all the Guests that have visitor_id = $id (the same for Registration).
$this->Visitor->Guest->deleteAll(array('visitor_id' => $id));
$this->Visitor->Registration->deleteAll(array('visitor_id' => $id));
this will delete all the Guests and the Registrations of the Visitor without touching the Visitor itself
you can try it,its worked for me
public function your_action($id=null){
$this->MainMdel->ConnectedModel1->deleteAll(array('ConnectedModel_id' => $id));
$this->MainMdel->ConnectedModel2->deleteAll(array('ConnectedModel_id' => $id));
}

Cakephp join query Belongs to

hello I have three tables in my database. Country, State,and City. In state table there is a country_id as foreign key and in city table there is state_id as foreign key. The problem is I want to get the country name when I am querying in the city table. I'll share the code so you can fully understand
Country.php
class Country extends AppModel{
public $useTable = 'countries';
}
State.php
class City extends AppModel{
public $useTable = 'cities';
public $belongsTo = array(
'State' => array(
'className' => 'State',
'foreignKey' => 'state_id',
'fields' => array('state.id','state.name')
)
);
}
City
class State extends AppModel{
public $useTable = 'states';
public $belongsTo = array(
'Country' => array(
'className' => 'Country',
'foreignKey' => 'country_id',
'fields' => array('Country.id','Country.name','Country.short_name')
)
);
okay here is the code. If I use this query
$this->State->find('all', array(
'conditions' => array(
'state.country_id' => $country_id
),
I can get the country name from country table. same is the case If I do this in city table like this
$this->City->find('all', array(
'conditions' => array(
'city.state_id' => $state_id
),
I can get all the state names city names here. So Now in this same table in one query how I can get the country name as well ?
Try using the recursive property.
Setting $this->City->recursive = 2 gets associated data for the table and associated data on the associated tables.
$this->City->recursive = 2;
$this->City->find('all', array(
'conditions' => array(
'city.state_id' => $state_id
),
//other stuff you use in this find
));
You can also using the "joins" flag.
$this->City->find('all', array(
'conditions' => array(
'City.state_id' => $state_id
),
'joins' => array(
array(
'table' => 'states',
'alias' => 'State',
'type' => 'left',
'conditions' => 'State.id = City.state_id'
),
array(
'table' => 'countries',
'alias' => 'Country',
'type' => 'left',
'conditions' => 'Country.id = State.country_id'
)
),
'fields' => array('City.id', 'State.name', 'Country.name',
//include all the fields you need
)
));
See: http://book.cakephp.org/2.0/en/models/model-attributes.html#recursive
In addition to the first answer, make sure to contain the foreign key for the Country.
class City extends AppModel{
public $belongsTo = array(
'State' => array(
'className' => 'State',
'foreignKey' => 'state_id',
'fields' => array('State.id','State.name', 'State.country_id'), // Make sure to contain the foreign key for the `Country`.
)
);
}
For your information, you can also use ContainableBehavior instead of recursive.
http://book.cakephp.org/2.0/en/core-libraries/behaviors/containable.html

Cakephp hasOne Model and hasAndBelongsToMany Model

I am having problems with the CakePHP belongsTo and hasAndBelongsToMany relationships in CakePHP 2.x
Example situation
Table users
id
organisation_id
Table organisations
id
name
Table user_organisation_permissions
id
user_id
organisation_id
UserModel
hasAndBelongsToMany(Organisation);
belongsTo(Organisation)
A user belongs to one organisation but it has permissions on multiple organisations, resulting in the following conflict:
$aUser = $this->User->findById(1);
print_r($aUser);
// Output
# With the belongsTo relation
array(
'User' => array(
'id' => 1,
'organisation_id' => 1
'name' => 'Test User'
),
'Organisation' => array(
'id' => 1,
'name' => 'Test organisation'
)
);
# With the hasAndBelongsToMany relation
array(
'User' => array(
'id' => 1,
'organisation_id' => 1
'name' => 'Test User'
),
'Organisation' => array(
1 => array(
'id' => 1,
'name' => 'Test organisation'
),
2 => array(
'id' => 1,
'name' => 'Test organisation'
)
)
);
# When both relations are enabled it doesn't work
Does anybody have a solution for this conflict?
Is there a "native" CakePHP solution for this conflict?
The answer is actually in the CakePHP 2.x Cookbook.
Multiple relations to the same model
There are cases where a Model has more than one relation to another Model. For example, you might have a Message model that has two relations to the User model: one relation to the user who sends a message, and a second to the user who receives the message. The messages table will have a field user_id, but also a field recipient_id. Now your Message model can look something like:
class Message extends AppModel {
public $belongsTo = array(
'Sender' => array(
'className' => 'User',
'foreignKey' => 'user_id'
),
'Recipient' => array(
'className' => 'User',
'foreignKey' => 'recipient_id'
)
);
}
Source: http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#multiple-relations-to-the-same-model

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 - contain (containable behavior) fetches too much

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.

Categories