How can I do a join with last entries in CakePHP? - php

So, I'm trying to do a query to get the last entries of each user using CakePHP relationship. In my Map and User model I have:
class Map (and User) extends AppModel {
public $hasMany = 'Geolog';
}
And I'm trying to doing this query to catch the last entry of each user. dg_maps and dg_users have a many to many relation.
SELECT
dg_users.id,
dg_users.email,
dg_maps.id,
dg_maps.latitude,
dg_maps.longitude,
dg_maps.timestamp
FROM
(SELECT
*
FROM
dg_maps
ORDER BY dg_maps.timestamp DESC) dg_maps
JOIN
dg_geologs ON dg_geologs.map_id = dg_maps.id
JOIN
dg_users ON dg_users.id = dg_geologs.user_id
GROUP BY dg_geologs.user_id;
What I'm doing now is:
$this->Map->query('SELECT dg_users.id, dg_users.email, dg_maps.id, dg_maps.latitude, dg_maps.longitude, dg_maps.timestamp FROM (SELECT * FROM dg_maps ORDER BY dg_maps.timestamp DESC) dg_maps JOIN dg_geologs ON dg_geologs.map_id = dg_maps.id JOIN dg_users ON dg_users.id = dg_geologs.user_id GROUP BY dg_geologs.user_id');
But, I know that a better method then this, using Cake methods. So, how can I do this?
Thank you all!

I used this for my project it is very simple
Easy way to generate CakePHP HABTM joins for use in pagination.
So put this in your model (note for function arguments - there is error in function from link )
public function generateHabtmJoin ($joinModel, $joinType = 'INNER') {
// If the relation does not exist, return an empty array.
if (!isset($this->hasAndBelongsToMany[$joinModel])) {
return array();
}
// Init joins, and get HABTM relation.
$joins = array();
$assoc = $this->hasAndBelongsToMany[$joinModel];
// Add the join table.
$bind = "{$assoc['with']}.{$assoc['foreignKey']} = {$this->alias}.{$this->primaryKey}";
$joins[] = array(
'table' => $assoc['joinTable'],
'alias' => $assoc['with'],
'type' => $joinType,
'foreignKey' => false,
'conditions' => array($bind),
);
// Add the next table.
$bind = "{$joinModel}.{$this->{$joinModel}->primaryKey} = {$assoc['with']}.{$assoc['associationForeignKey']}";
$joins[] = array(
'table' => $this->{$joinModel}->table,
'alias' => $joinModel,
'type' => $joinType,
'foreignKey' => false,
'conditions' => array($bind),
);
return $joins;
}
and you can call this function from your controller
You have example in link

Related

Comparing two active records in yii2

I have two models in yii2 which are related . I would like to compare them such that using an id i get the id values in a not in b
That is
I have a pr model and pr items model and i would like to get the id values in pr model not in pritems model
I have tried
$pr = Tblpr::find()->all(); //This returns all pr model items
$pritems = Tblpritems::find()->all() //this returns all pritems
$pr and $pritems are related by id such that id in pritems is a foreign key referencing pr
How can i get the ids in pr but not in pritems.
There are several way
You can try with findBySql (using a subquery )
$sql = 'SELECT * FROM tblpr as a
where a.id not in (select b.id
Tblpritems as b)';
$model = Tblpr::findBySql($sql)->all();
or using left join
$sql = 'SELECT * FROM tblpr
left join Tblpritems on tblpr.id = Tblpritems. id
where wTblpritems.id is null';
$model = Tblpr::findBySql($sql)->all();
Or you can use activeQuery
$query = Tblpr::find();
$query->leftJoinWith('tblpritems', 'tblpr.id = tblpritems.id');
$query->andWhere(['pritems.id' => null]);
$model = $query->all();
for dataProviding you can
$provider = new ActiveDataProvider([
'query' => $sql,
'pagination' => [
'pageSize' => 20,
],
]);
Just join relatated table and check it ids for null:
$query = Tblpr::find();
$query->innerJoinWith('tblpritems', false);
$query->andWhere(['pritemsId' => null]);
$prWithOutItems = $query->all();
It's better to extend it to TblprQuery and use like Tblpr::find()->withoutItems()->all().

CakePHP - deleting data by associated key

I have a few tables that are joined through a distant relationship - for example:
A.id = B.a_id, B.id = C.b_id, C.id = D.c_id
And given A.id, I want to delete all the rows in D that are associated with A.id.
Since Model::deleteAll() does not accept any joins, only conditions, how do I go about it?
All the models (A, B, C, D) already have belongTo relationships defined.
My last resort would be raw SQL, but I would like to know if there's a way in CakePHP to do it.
I could not find similar questions as they all were about deleting ALL the associated data, rather than just one table's data via an associated key.
Use Containable behavior to find D records
public function deleteD($idA){
$this->ModelA->Behaviors->load('Containable');
$options = array(
'contain' => array(
'ModelB' => array(
'ModelC' = array(
'ModelD'
)
)
),
'conditions' => array('ModelA' => $idA)
);
$findDIds = $this->ModelA->find('all',$options);
debug($findDIds); // find right path to ModelD
$ids = Hash::extract($findDIds,'{n}.ModelD.id');
$this->loadModel('ModelD');
foreach($ids as $id){
$this->ModelD->delete($id);
}
}
Note, I not tested this function.

cake php custom query

I have use custom query in cakephp but I dont understand how to run custom join query.
I am using this code
$arrayTemp1 = $this->User->query('SELECT DISTINCT
u.id,u.hunting_association FROM ht_users as u LEFT JOIN
`ht_user_animal_prices` as uap ON uap.user_id=u.id WHERE
uap.animal_type_id='.$this->request->data['User']['animal'].' ');
User is the model for ht_users and UserAnimalPrice is the model for ht_user_animal_prices. How to combine the query?
Please help.
If you want to use custom queries and you want the data of UserAnimalPrice model, you just have to put the fields in the query. Something like:
$arrayTemp1 = $this->User->query('SELECT DISTINCT u.id,u.hunting_association, uap.* FROM ht_users as u LEFT JOIN ht_user_animal_prices as uap ON uap.user_id=u.id WHERE uap.animal_type_id='.$this->request->data['User']['animal'].' ');
If you prefer not to use custom queries:
$fields = array('User.id','User.hunting_association','UserAnimalPrice.*');
$join = array(
array(
'table' => 'ht_user_animal_prices',
'alias' => 'UserAnimalPrice',
'type' => 'LEFT',
'conditions' => array('UserAnimalPrice.user_id = User.id')
)
);
$conditions = array('UserAnimalPrice.animal_type_id' => $this->request->data['User']['animal']);
$group = array('User.id');
arrayTemp1=arrayTemp1->find('all',array('fields'=>$fields,'joins'=>$join,'conditions'=>$conditions,'group'=>$group));
This is Correct Query u used .You can also use it in User Model like
public function getCustomUsersQuery()
{
$arrayTemp1 = $this->query("
SELECT
DISTINCT u.id,u.hunting_association FROM ht_users as u
LEFT JOIN
ht_user_animal_prices as uap ON uap.user_id=u.id
WHERE
uap.animal_type_id='".$this->request->data['User']['animal']."'");
return $arrayTemp1;
}
And call inside Users Controller
$result = $this->getCustomUsersQuery();
Sorry I cannot comment on Rizwan answer. If you received the "Call to a member function..." problem, make sure you have the following code
public $uses = array('User');
this tells that you want to access the user model in that controller. Then you will be allowed to do so.

Condition for related table ORM Kohana

For example I have 3 tables:
songs(id, song_name)
song_category(id, song_id, category_id)
categories(id, name)
I want to get songs which have categories with id higher than 5. I want to do it using ORM, not with simple SQL query. Is it possible to do it with one query like this:
$songs = ORM::factory("songs")->where("category.id > 5")
No, you cannot do this with a single Kohana ORM call.
The best way I have found to do it is something like this, which makes a modification to the SQL query that the ORM will generate:
// Get the basic "song" model
$songs = ORM::factory("songs");
// Get the information about how it is connected to
// the "category" model using the `through` model
$song_relations = $results->has_many();
$category_relation = $song_relations['categories'];
$through = $category_relation['through'];
// Join on `through` model's target foreign key (far_key) and `target` model's primary key
$join_col1 = $through.'.'.$category_relation['foreign_key'];
$join_col2 = $songs->object_name().'.'.$songs->primary_key();
$songs->join($through)->on($join_col1, '=', $join_col2);
// Now, filter on the
$songs->where($through.'.'.$category_relation['far_key'], '>', 5);
$arr = $results->find_all()->as_array();
You could save some code by hardcoding the values in the join method call, but this way leverages the ORM relation definitions that you already have.
This assumes that your Song model has the following code in it:
protected $_has_many = [
'categories' => [
'model' => 'category',
'through' => 'song_category',
'foreign_key' => 'song_id',
'far_key' => 'category_id',
]
];

converting SQL to cakephp ORM

So I have this query that I am trying to convert to cake ORM and I do not know how to go about it.
I have a user table and a word table. Users have many words (thats the relationship). I want to write a query that will give me the users that have added the most words in the system. This is the current query I wrote but I am having trouble converting it to cakephp ORM syntax, any ideas?
SELECT
users.username,
COUNT(word) AS n
FROM
users AS users
INNER JOIN words AS words
ON users.userid=words.userid
GROUP BY
users.username
ORDER BY
n DESC
LIMIT 3
There are many ways to write the query:- In controller you can write as -
$options = array(
'fields' => array(
'User.name',
'COUNT(Word.id) as word_count',
),
'group' => 'Word.user_id',
'order' => 'word_count DESC',
);
$users = $this->User->Word->find('first', $options);
debug($users);
In User model you have to write:
public $hasMany = 'Word';
In Word model you have to write:
public $belongsTo = 'User';

Categories