CakePHP find method with JOIN
There are two main ways that you can do this. One of them is the standard CakePHP way, and the other is using a custom join.
It's worth pointing out that this advice is for CakePHP 2.x, not 3.x.
The CakePHP Way
You would create a relationship with your User model and Messages Model, and use the containable behavior:
class User extends AppModel {
public $actsAs = array('Containable');
public $hasMany = array('Message');
}
class Message extends AppModel {
public $actsAs = array('Containable');
public $belongsTo = array('User');
}
You need to change the messages.from
column to be messages.user_id
so that cake can automagically associate the records for you.
Then you can do this from the messages controller:
$this->Message->find('all', array(
'contain' => array('User')
'conditions' => array(
'Message.to' => 4
),
'order' => 'Message.datetime DESC'
));
The (other) CakePHP way
I recommend using the first method, because it will save you a lot of time and work. The first method also does the groundwork of setting up a relationship which can be used for any number of other find calls and conditions besides the one you need now. However, cakePHP does support a syntax for defining your own joins. It would be done like this, from the MessagesController
:
$this->Message->find('all', array(
'joins' => array(
array(
'table' => 'users',
'alias' => 'UserJoin',
'type' => 'INNER',
'conditions' => array(
'UserJoin.id = Message.from'
)
)
),
'conditions' => array(
'Message.to' => 4
),
'fields' => array('UserJoin.*', 'Message.*'),
'order' => 'Message.datetime DESC'
));
Note, I've left the field name messages.from
the same as your current table in this example.
Using two relationships to the same model
Here is how you can do the first example using two relationships to the same model:
class User extends AppModel {
public $actsAs = array('Containable');
public $hasMany = array(
'MessagesSent' => array(
'className' => 'Message',
'foreignKey' => 'from'
)
);
public $belongsTo = array(
'MessagesReceived' => array(
'className' => 'Message',
'foreignKey' => 'to'
)
);
}
class Message extends AppModel {
public $actsAs = array('Containable');
public $belongsTo = array(
'UserFrom' => array(
'className' => 'User',
'foreignKey' => 'from'
)
);
public $hasMany = array(
'UserTo' => array(
'className' => 'User',
'foreignKey' => 'to'
)
);
}
Now you can do your find call like this:
$this->Message->find('all', array(
'contain' => array('UserFrom')
'conditions' => array(
'Message.to' => 4
),
'order' => 'Message.datetime DESC'
));
Issue with CakePHP 2 find method with JOIN
You can use below query
$joins = array(
array('table' => 'orders',
'alias' => 'Order',
'type' => 'INNER',
'conditions' => array(
'Order.customer_id = Customer.id',
)
)
);
$conditions = [];
$conditions[] = ['Customer.type' => 2];
$conditions[] = ['Customer.status'=>1];
$this->Customer->virtualFields['total_due'] = "sum(Order.due_amount)";
$data_array = $this->Customer->find('all', ['conditions' => $conditions, 'group' => 'Customer.id', 'joins' => $joins, 'fields' => ['Customer.*', 'Customer.total_due']]);
Join query retrieving data from only one table cakephp 3
Manually adding joins won't cause any additional data to be selected, you'd have to do that on your own by specifying the fields to be selected via the select()
method.
$events = $events_table
->find('all')
->hydrate(false)
->select($events_table)
// either add the fields one by one, or pass a table object
// as above to select all fields of the table
->select(['CourseType.id', 'CourseType.xyz', /* ... */])
// ...
I'd suggest to use use containments instead, ie setup the required association if not already present, and then simply use contain()
:
$events = $events_table
->find('all')
->hydrate(false)
->contain('CourseType')
->where(['Events.id' => $id]);
See also
- Cookbook > Database Access & ORM > Query Builder > Selecting Data
- Cookbook > Database Access & ORM > Query Builder > Loading Associations
How to make a Join on query with Cakephp?
Chnage your relationships to something like this:
$this->belongsTo('Commenters', [
'className' => 'Users',
'foreignKey' => 'commentator_id',
'joinType' => 'INNER'
]);
$this->belongsTo('Users', [
'foreignKey' => 'commented_id',
'joinType' => 'INNER'
]);
So then you can contain the two different relationships.
$comments = TableRegistry::getTableLocator()
->get('Comments')
->find('all')
->contain(['Commenters', 'Users']);
And access them like this:
$comment->commenter->name; // Name of the person who commented
$comment->user->name; // Name of the person who was commented on
Cakephp 3 findAuth join table return array
What I finally ended up going with is this:
public function findAuth(\Cake\ORM\Query $query, array $options)
{
$query
->select(['id', 'username', 'passwordHash', 'locked'])
->join([
'table' => 'user_roles',
'conditions' => ['user_roles.user_id = Users.id']])
->contain(['UserRoles.Roles'])
->join([
'table' => 'roles',
'conditions' => ['roles.id = user_roles.role']])
->group(['Users.username']);
return $query;
}
This gives me a multi-dimensional array of:
user_roles[index[id, user_id, roles[id, role]]]
in my case I have 2 entries for the index (0 and 1) and I can check the role of the user with the in_array function within a foreach loop
Cakephp 3 join satetment with where clause
The option is named join
(singular), not joins
, just like the corresponding query builder method.
I would also suggest that you look into setting up associations for your relationships, which would then allow you to use the innerJoinWith()
and leftJoinWith()
methods (among others), making your query building much easier.
Also note that you need to manually specify the fields the fields that you want to select from the joins.
See also
- Cookbook > Database Access & ORM > Retrieving Data & Results Sets > Using Finders to Load Data
- Cookbook > Database Access & ORM > Associations - Linking Tables Together
- Cookbook > Database Access & ORM > Query Builder > Loading Associations
Related Topics
Codeigniter Displays a Blank Page Instead of Error Messages
PHP Fileinfo Is Undefined Function
What Does the "[^][]" Regex Mean
Pinging an Ip Address Using PHP and Echoing the Result
Parse an Xml With Simplexml Which Has Multiple Namespaces
PHP/MySQL With Multiple Queries
The Character Encoding of the HTML Document Was Not Declared
How to Upload & Save Files With Desired Name
Accessing Outside Variable Using Anonymous Function as Params
In PHP (≫= 5.0), Is Passing by Reference Faster
PHP: Recreate and Display an Image from Binary Data
Redefine Class Methods or Class
How to Create a Copy of an Object in PHP
Search For a Key in an Array, Recursively
PHP 5 Disable Strict Standards Error