Cakephp how to join table on a specific field - cakephp

Someone can help me on this issue please?
How to join table on specific field?
I have 2 tables and I want to join them like this: Actus.user_id=>Follows.follower_id
table 1 =>
Follows
id
user_id
follower_id
table 2 =>
Actus
id
user_id
content
created

Forcing a join is done like this (on top of my head):
<?php
$results = $this->Actu->find('all',
array('joins'=> array(
'table'=>'followers',
'type'=>'inner',
'alias'=>'Follower',
'conditions'=>array(
'Follower.follow_id = Actu.user_id',
)
)
)
?>
But you would normally don't need forcing joins. CakePhp can build this for you, if your Models (Actu and Follower) are declared properly. What about setting a "Actu" hasMany "Follower" relationship ? See here
EDIT :
I would do it like this (I am not sure about the exact model name, double check it) :
<?php
class Actu extends AppModel {
public $hasMany = array(
'Follow'=> array(
'className' => 'Follow',
'foreignKey' => 'follower_id'
)
);
}
?>

Related

ID fields not auto filled for table with multiple associations (CakePHP)

I'm working on a customer database. For larger business customers the relationships get a little complicated. It's almost working but one ID field is not being automatically filled.
I have 3 models, Customer, CustomerAddress and CustomerContact. A customer can have many addresses, and many contacts, but the contacts are also based at one address so an address has many contacts.
Database:
customer has id
customer_addresses has customer_id
customer_contacts has customer_id, customer_address_id
Models:
class Customer extends AppModel {
public $hasMany = array(
'CustomerContact',
'CustomerAddress',
);
....
}
class CustomerAddress extends AppModel {
public $belongsTo = array(
'Customer',
);
public $hasMany = array(
'CustomerContact',
);
....
}
class CustomerContact extends AppModel {
public $belongsTo = array(
'Customer',
'CustomerAddress',
);
....
}
I have one form that adds fields for all 3 models, and I'm calling '$this->Customer-saveAll' in the controller. It saves everything just fine, but doesn't fill in the 'customer_address_id' field in the 'customer_contacts' table.
I've tried changing the relationship in contacts to belongs to address, I've tried renaming the field to customer_addresses_id (made it pleural) just incase it was a quirk with Cake's internal naming, but it still doesn't fill the address ID field.
My workaround is to update the contact after the saveAll command in the controller, since the address has it's id set at this point:
$this->CustomerContact->saveField( 'customer_address_id', $this->CustomerAddress->id);
This is my first project with Cake and it seems really good at doing this stuff by itself, so I'm wondering if I've got something wrong somewhere.
TIA!
EDIT:
After going through the associations again, I changed the association on CustomerContact from hasOne to belongsTo CustomerAddress because I realised I got it wrong.
I tried 2 different ways of submitting the data:
'Customer' => .... data ....
'CustomerAddress' => array(
(int) 0 => array(
'CustomerContact' => array(
(int) 0 => array(
.... data ....
)
),
.... data ....
)
)
This sets the customer_address_id field on the contact, but not customer_id.
'Customer' => .... data ....
'CustomerAddress' => array(
(int) 0 => array(
.... data ....
)
),
'CustomerContact' => array(
(int) 0 => array(
.... data ....
)
)
This sets the customer_id but not the customer_address_id.

CakePHP Join virtualField as displayField

I'm trying to do one of two things, use a virtual field from a model as the display field in my join model, or use the virtual field as the display in a find('list') on my join model.
Here's the current layout:
MODELS
<?php
class Participant extends AppModel {
public $hasMany = array('Registration');
public $virtualFields = array(
'full_name' => 'CONCAT(last_name, ", ", first_name)'
);
public $displayField = 'full_name';
}
-----
class Contest extends AppModel {
public $hasMany = array('Registration');
}
-----
class Registration extends AppModel {
public $belongsTo = array('Participant', 'Contest');
public $hasMany = array('Assignment');
}
?>
Tables are as follows:
participants contests registrations
------------ --------- --------------
id id id
first_name name contest_id
last_name participant_id
In my contests controller I'm trying to develop a list to be viewed as checkboxes in the view.
Here is the excerpt from my contests controller:
$this->loadModel('Registration');
$this->set('registrations', $this->Registration->find(
'list',
array(
'conditions' => array('contest_id' => $contestId),
'recursive' => 1
)
)
);
//$contestId is defined previously, and I have verified such.
This all actually runs fine as it is, and in the view will display a column of checkboxes with the registration_id as the label next to the checkbox.
I would like to get a full_name as is defined in the Participant model to be the displayField of the Registration model. I've been searching and can't quite seem to find a good way of doing that. I hope I have been descriptive enough, and please let me know if you have any questions and I'll try to explain better. Thank you.
edit: I'm using CakePHP 2.4.
try to add the 'fields' parameter
$this->loadModel('Registration');
$this->set('registrations', $this->Registration->find(
'list',
array(
'fields' => array('Registration.id', 'Participant.full_name'),
'conditions' => array('contest_id' => $contestId),
'recursive' => 1
)
));
edit: apparently cake does not place virtual fields of associated models when using find() with 'fields' options.
So you have to build your array by yourself, hoping your models use the containable behavior
$registrations = $this->Registration->find(
'all',
array(
'contain' => array(
'Participant' => array('full_name')
),
'conditions' => array('contest_id' => $contestId),
)
);
$registrations = Hash::combine($registrations, '{n}.Registration.id', '{n}.Participant.full_name');
$this->set('registrations', $registrations);

Virtual Fields as aliases to other Model field - SQL: Unknown Column Error

I'm new to an existing Cake project where we are trying to use a virtualField within a model to alias another model field. In Context:
class Product extends AppModel {
var $name = 'Product';
var $hasOne = array('ProductPrice');
var $virtualFields = array(
'price' => 'ProductPrice.current_price'
);
// Typical fields in the database for Product. id, name, etc.
}
class ProductPrice extends AppModel {
var $name = 'ProductPrice';
var $belongsTo = array('Product');
// Fields are product_id, current_price
}
The ProductPrice model is for a view in the database that contains different price tiers with a current_price column allowing retrieval of the current price of the product. When accessing the Product model via something like:
$this->Product->find('all' ....);
I don't have any problems with getting the price field. The problem is if the query to Product is done indirectly through something like
$this->Inventory->find('all');
We get:
SQL Error: 1054: Unknown column 'ProductPrice.current_price' in 'field list' [CORE/cake/libs/model/datasources/dbo_source.php, line 681]
I know that the issue is that the SQL generated by the Inventory query does not attempt to join the ProductPrice view. I assumed that this would happen automagically via the Product model as it knows it "hasOne" ProductPrice.
I've tried setting "recursive" on the Inventory model to 2,1, etc. with no success.
What am I missing?
TLDR:
You cannot use fields from a different model in a VirtualField.
Other options:
If you're doing a query like:
$this->Inventory->find('all');
You can use something like CakePHP's Containable behavior to make sure you're getting the data you want:
//controller code
$inv = $this->Inventory->getInventory();
//model code
class Inventory extends AppModel {
public $actsAs = array('Containable');
public function getInventory() {
return $this->find('all', array(
'contain' => array(
'Product' => array(
'ProductPrice'
)
)
));
}
}
Using containable like in the above code example should return the data in a format something like this:
[0] => Array
(
[Inventory] => Array
(
[id] => 12345
)
[Product] => Array
(
[0] => Array
(
[id] => 54321
[title] => product A
)
[ProductPrice] => Array
(
[id] => 6789
[current_price] => 24.99
)
)
//...
When you get the data like that, it should be easy to access the Product's current price.
You could also just do it in the controller, but it's better practice to keep your queries in the model to stay within the "Fat Model, Skinny Controller" mantra. If you really want to keep it in your controller, you can just do this:
$inv = $this->find('all', array(
'contain' => array(
'Product' => array(
'ProductPrice'
)
)
);
(BUT - you still have to specify that a model $actsAs Containable (per first code example).

Add a friend feature in CakePHP

I need a simple add a friend feature in my application, through some research, I would need a join table linking back to users table ? something like this: (I already have a users table)
Users-Friendships-Users
Can anyone give more details about this?
The friendships table should have following columns:
id Integer
user_from (the user who requested friendship)
user_to (the user who accepted friendship)
created (optional to track when your friendship started)
Then you need to create proper Model relation.
class User extends AppModel {
...
var $hasMany = array(
'UserFrom'=>array(
'className'=>'Friendship',
'foreignKey'=>'user_from'
),
'UserTo'=>array(
'className'=>'Friendship',
'foreignKey'=>'user_to'
)
);
var $hasAndBelongsToMany = array(
'Friendship' => array(
'className' => 'User',
'joinTable' => 'friendships',
'foreignKey' => 'user_from',
'associationForeignKey' => 'user_to'
);
...
}
class Friendship extends AppModel {
...
var $belongsTo = array(
'UserFrom'=>array(
'className'=>'User',
'foreignKey'=>'user_from'
),
'UserTo'=>array(
'className'=>'User',
'foreignKey'=>'user_to'
)
)
...
}
This way you are defining 2 relation in each model. You can add HABTM relation too. Run bake script to build your controllers and views. Then in your code you can use something like this:
$this->User->UserFrom->find('all',
array(
'conditions'=>array('user_from'=>1),
'contain'=>array('UserTo')
)
);
This should return friends of user with ID 1 and all friends details.
Be careful with the recursive queries. :)

Cakephp: HasOne Relationship

I'm trying to model the following:
A journey has an id, a fromCity and a toCity.
My DB looks like this:
Table journey:
id | fromCity | toCity
1 2 4
2 4 2
Table fromCity:
id | name
2 paris
4 london
I have models defined for the city and for the journey.
In my model file for the journey I want to declare a $hasOne filed in order resolve the fromCity id to the city's name.
I tried to follow the CakePHP tutorial on hasOne (http://book.cakephp.org/view/80/hasOne) but I can't wrap my head around how to resolve two foreign keys.
Can someone please explain to me how a var $hasone = ... has to look for this case?
Edit: The models:
<?php class City extends AppModel { var $name='City';} ?>
<?php class Journey extends AppModel { var $name='Journey'; /*var $hasOne=array(...)*/} ?>
Edit 2:
var $hasOne = array(
'CityFrom' => array(
'className' => 'City',
'conditions' => 'Journey.fromAirport = CityFrom.id',
'dependent' => true,
'foreignKey' => 'id = Journey.fromCity' ),
'CityTo' => array (
'className' => 'City',
'conditions' => 'Journey.toCity = CityTo.id',
'dependent' => true,
'foreignKey' => 'id = Journey.toCity'
)
);
Seems to work for the first entry of the journey table. All other's values are null. I think the problem occours from having two columns with the same name in this query.
As Rin mentioned,you need to use beLongsTo instead of hasOne.Here's a example about Multiple relations to the same model from Cookbook.Hope it helps.
First of all your link leads to 1.2 docs, you probably downloaded 1.3.
In 1.3, you should probably also use belongsTo on FromCity and ToCity Models (but I could be wrong, long time ago I used it :)

Resources