Sql query to cakephp query using associations - php

Here is my correct sql query:
SELECT * FROM `messages` WHERE ( (sender_id=3 AND user_id=40) OR (sender_id=40 AND user_id=3)) AND offer_id=1
I want to use this in Cakephp syntax:
$this->Message->find('all',array('conditions'=>array(
'AND'=>array(
'OR'=>array(
'Message.offer_id'=>$offer_id,
'Message.sender_id'=>$sender_id,
'Message.user_id'=>$this->Auth->user('id'),
),
'OR'=>array(
'Message.offer_id'=>$offer_id,
'Message.user_id'=>$sender_id,
'Message.sender_id'=>$this->Auth->user('id')
)
)
),
'recursive'=>2
));
Is there anyone who can help me to figure out the issue. Basically I want to get all the messages whether I sent or received for an particular offer.

You should move $offer_id out of or conditions and move it to and conditions.
Why? Lets look at your first or array:
That conditions will return true if:
sender_id is 3
OR user_id is 40
OR offer_id is 1
So, that condition may return true event if offer_id != 1
That should be written this way (as precisely as possible according to original query):
$query = $this
->Messages
->find('all' , [
'conditions' => [
'or' => [
[
'sender_id' => $sender_id,
'user_id' => $this->Auth->user('id')
], [
'sender_id' => $this->Auth->user('id'),
'user_id' => $sender_id
]
],
'offer_id' => $offer_id,
]
]);
dump($query);
In dump we can see something like this:
"SELECT * FROM messages Messages WHERE (((sender_id = :c0 AND user_id = :c1) OR (sender_id = :c2 AND user_id = :c3)) AND offer_id = :c4)
asterisk in sql query dump for more readability

You have the AND and OR operators reversed.
'OR'=>array(
'AND'=>array(
'Message.offer_id'=>$offer_id,
'Message.sender_id'=>$sender_id,
'Message.user_id'=>$this->Auth->user('id'),
),
'AND'=>array(
'Message.offer_id'=>$offer_id,
'Message.user_id'=>$sender_id,
'Message.sender_id'=>$this->Auth->user('id')
)
)

Related

Get all rows where the field is not NULL in CakePHP 3

How can I get all the instances of a Table where the fields are not NULL ?
Here is the configuration:
I have a Table 1 where the instances have a relationship "hasmany" with a Table 2. I want to get all the instances of Table 1 linked with a Table 2 instance not NULL.
The CakePHP doc helped me finding the exists() and isNotNull() conditions but I did not achieve.
Here is how I imagined:
$Table1 = TableRegistry::get('Table1')->find('all')->contain([
'Table2' => [
'sort' => ['Table2.created' => 'desc']
]
])->where([
'Table1.id' => $id,
'Table2 IS NOT NULL'
]);
$this->set(compact('Table1'));
But it obviously does not work.
edit : I expect to get all the line of the Table1 which contain existing Not NULL Table2 line(s) linked. The problem is in the 'where' array with the 'Table2 IS NOT NULL', it does not work.
And without this line 'Table2 IS NOT NULL', I get all the Table1 line which contain a Table2 line or not (because some line of Table1 are not linked at all and I don't want to get these lines).
Assuming the tables follow convention and use "id" as the primary key, I suggest the easiest fix would be testing that field for NOT NULL.
I.e., replace this:
'Table2 IS NOT NULL'
with this:
'Table2.id IS NOT NULL'
or:
'Table2.id !=' => null
or:
'Table2.id >' => 0
I've successfuly get the Table1 lines with its existing Table2 line(s) associated.
query = TableRegistry::get('Table1')->find();
$query->select(['Table1.id', 'count' => $query->func()->count('Table2.id')])->matching('Table2')->group(['Table1.id'])->having(['count
>' => 0]);
$table1Ids = [];
foreach ($query as $z)
{
$table1Ids[] = $z->id;
}
$table1= TableRegistry::get('Table1')->find('all')->contain([
'Table2' => [
'sort' => ['Table2.created' => 'desc']
]
])->where([
'id IN' => $table1Ids,
]);

How to write a custom query in dynamodb using php?

In my case I have a table name "friends" which has two attributes:
account_id
fb_id
I try to get all the account_id based on fb_id, and for this wrote the query as below:
$response = $dynamoClient->getItem ( array(
"TableName" => "facebook_friendlist",
"ConsistentRead" => true,
"Key" => array(
"fb_id" => array(
"S" => "171092723281123"//$fbId
)
),
"ProjectionExpression" => "account_id"
) );
But its not getting executed. I also tried to write the same query using getItem(),scan(),getIterator() but no result.
Help me out with the right way. Thanks in advance.

CakePHP not joining the correct tables in find query

OK, another cake question from me.
I have rather a complex table structure with quite a few joins. Here's the jist of it:
So, in summary:
RiskCategory $hasMany Client [Client $belongsTo RiskCategory]
Client $hasMany Account [Account $belongsTo Client]
Account $hasMany Holding [Holding $belongsTo Account]
In my RiskCategory model I want to run a query that basically returns the sum of the holdings in each riskCategory id, grouped by date. There's a few other conditions but here is what I've put together:
$findParams = array(
'recursive' => 4,
'fields' => array(
'Holding.holding_date',
'SUM(Holding.value) AS risk_category_value'
),
'group' => array('Holding.holding_date'),
'order' => 'Holding.holding_date ASC'
);
$findParams['conditions'] = array(
'Client.active' => true,
'Client.model' => true,
'Client.currency' => 'GBP',
'OR' => array(
'Holding.holding_date' => $this->end_date,
array(
'Holding.holding_date = LAST_DAY(Holding.holding_date)',
'MONTH(Holding.holding_date)' => array(3,6,9,12)
)
)
);
$valuations = $this->Client->Account->Holding->find( 'all', $findParams );
When I run the above cake is giving me an error saying various fields are not present in the query. The raw query created is as follows:
SELECT `Holding`.`holding_date`,
Sum(`Holding`.`value`) AS risk_category_value
FROM `ips_client_db`.`holdings` AS `Holding`
LEFT JOIN `ips_client_db`.`accounts` AS `Account`
ON ( `Holding`.`account_id` = `Account`.`id` )
LEFT JOIN `ips_client_db`.`sedols` AS `Sedol`
ON ( `Holding`.`sedols_id` = `Sedol`.`id` )
WHERE `client`.`active` = '1'
AND `client`.`model` = '1'
AND `client`.`currency` = 'GBP'
AND ( ( `Holding`.`holding_date` = '2013-10-01' )
OR (( ( `Holding`.`holding_date` = Last_day(
`Holding`.`holding_date`) )
AND ( Month(`Holding`.`holding_date`) IN ( 3, 6, 9, 12 ) ) )
) )
GROUP BY `Holding`.`holding_date`
ORDER BY `Holding`.`holding_date` ASC
It looks as though cake is not doing all the joins. It is only joining Account to Holding and then Holding to Sedol (which is another joined table in the database but is not needed for this query so I've omitted it from the diagram)
Why are the joins not being made properly and how to acheive this? I'd like to avoid writing a raw statement if possible.
EDIT: The joins should be as follows:
...
FROM risk_categories
LEFT JOIN ((clients
LEFT JOIN accounts
ON clients.id = accounts.client_id)
LEFT JOIN holdings
ON accounts.id = holdings.account_id)
ON risk_categories.id = clients.risk_category_id
...
CakePHP does not perform deep joins for associations that are more than 1 level deep. That is why you're getting an error for references to the Client table in the conditions.
For these types of problems it's easier to use the Containable behavior. I usually add this behavior to my AppModel as the default handler for associations.
Containable allows you to define the associations (only those already defined) with their fields and conditions as part of the find operation. This is done by adding a new contain key in the find parameters. Below I've taking a guess at what you might need.
$findParams = array(
'fields' => array(
'Holding.holding_date',
'SUM(Holding.value) AS risk_category_value'
),
'conditions'=>array(
'OR' => array(
'Holding.holding_date' => $this->end_date,
array(
'Holding.holding_date = LAST_DAY(Holding.holding_date)',
'MONTH(Holding.holding_date)' => array(3,6,9,12)
)
)
),
'group' => array('Holding.holding_date'),
'order' => 'Holding.holding_date ASC',
'contain'=>array(
'Account'=>array(
'Client'=>array(
'RiskCategory',
'conditions'=>array(
'Client.active' => true,
'Client.model' => true,
'Client.currency' => 'GBP',
)
)
)
)
);
$valuations = $this->Client->Account->Holding->find( 'all', $findParams );

CakePHP query with AND OR

I have the following query which should be finding:
A row where the user_id matches userId and friend_id matches friendId
OR a row where the user_id matches friendId and friend_id matches userId
AND both also have status of 1
My code is:
public function isFriend($userId, $friendId)
{
return $search = $this->Friend->find('first', array(
'conditions'=>array(
'OR' => array(
'AND'=>array(
'Friend.user_id'=>$userId,
'Friend.friend_id'=>$friendId
),
'AND'=>array(
'Friend.user_id'=>$friendId,
'Friend.friend_id'=>$userId
)
),
'AND' => array(
'Friend.status'=>1
)
)
)
);
}
However it's not working... I've looked around and seems it's to do with getting the arrays correctly when dealing with the two AND calls, but I don't get it. Can anyone help me out?
Thanks
You can't use the same array key twice as mark said, so you have to encapsulate the ANDs in separate arrays
'OR' =>
array(
array('AND'=>array(
'Friend.user_id'=>$userId,
'Friend.friend_id'=>$friendId
)
),
array('AND'=>array(
'Friend.user_id'=>$friendId,
'Friend.friend_id'=>$userId
)
)
),
'AND' => array(
'Friend.status'=>1
)

how to use LIKE with conditions in sqlite or mysql with lithium recordset

so I can look for concrete values by doing
$recordset= Model::find('all', array(
'conditions' => array(
'condition' => $somevalue
)
))
however, what do I do if I want to match on a partial value?
right now, I've resorted to writing the query myself, a la:
$abc = Connections::get('default')->
read('SELECT * FROM myTable WHERE condition LIKE "%partial string%"');
Here's how I do an SQL 'like' search:
$user = User::find('all', array(
'conditions' => array(
'first_name' => array('like' => '%yeun%'))
)
);
'like' being the keyword, there.
That would generate a query like:
SELECT * FROM `users` AS `Users` WHERE (`first_name` like '%yeun%');
Hope that helps.

Categories