Comparing two active records in yii2 - php

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().

Related

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.

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

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

Yii Activerecord doesn't join with nested relation

I have defined the following criteria in Yii, and tries to use it to fetch an array of customers.
$criteria = new CDbCriteria(array(
"condition"=>"hidden = 0".(Yii::app()->user->GetState('is_admin') ? "" : " AND franchisesMunicipalities.franchise_id=".Yii::app()->user->getState('fid')),
"with" => array('municipality','municipality.franchisesMunicipalities')
));
$customers = Customers::model()->findAll($criteria);
This (i thought) should result in that Yii joined the table Customers with the table Municipalities, and then in the same query join the table Municipalities with the table Franchises_Municipalities. However it doesn't work since it doesn't join franchisesMunicipalities.
The resulting query is this
SELECT `t`.`id` AS `t0_c0`,
`t`.`municipality_id` AS `t0_c1`,
`t`.`personal_code_number` AS `t0_c2`,
`t`.`name` AS `t0_c3`,
`t`.`adress` AS `t0_c4`,
`t`.`zip` AS `t0_c5`,
`t`.`phone` AS `t0_c6`,
`t`.`mobile` AS `t0_c7`,
`t`.`email` AS `t0_c8`,
`t`.`hidden` AS `t0_c9`,
`municipality`.`id` AS `t1_c0`,
`municipality`.`county_id` AS `t1_c1`,
`municipality`.`name` AS `t1_c2`
FROM `customers` `t`
LEFT OUTER JOIN `municipalities` `municipality`
ON ( `t`.`municipality_id` = `municipality`.`id` )
WHERE ( hidden = 0
AND municipality.franchisesmunicipalities.franchise_id = 7 )
LIMIT 30
As you can see it only joins on one relation. The relations in the model should be correctly defined, since i am able to use them in other contexts.
Why doesn't this work?
According to http://www.yiiframework.com/doc/api/1.1/CActiveRecord#with-detail I believe you should be doing it this way:
$criteria = new CDbCriteria(array(
"condition"=>"hidden = 0".(Yii::app()->user->GetState('is_admin') ? "" : " AND franchisesMunicipalities.franchise_id=".Yii::app()->user->getState('fid'))
));
$customers = Customers::model()->with('municipality','municipality.franchisesMunicipalities')->findAll($criteria);
Hopefully that works for you.

Doing Join query using CDBCriteria

I am trying to do a Join query using CDBCriteria in Yii framework. The issue is the join query works successfully but it does not display the columns from other tables.
I am doing in the following way
$criteria = new CDbCriteria;
$criteria->order = 't.id desc';
$criteria->select = '*';
$criteria->join = ' INNER JOIN table2 INNER JOIN table3 INNER JOIN table4';
When i run this, I can see only the mail table1 columns displayed. Other columns are not shown.
In my model class, I have the relation has
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'user' => array(self::BELONGS_TO, 'DmPhoneUser', 'user_id'),
'command' => array(self::BELONGS_TO, 'DmOtaCommand', 'command_id'),
'partner' => array(self::BELONGS_TO, 'DmPartner', 'partner_id'),
);
}
********************************************************
public function actionGetHistory($start, $per_page)
{
$partner_id = '10';
$criteria = new CDbCriteria;
$criteria->order = 't.history_id desc';
$criteria->select = 't.*, table2.*';
$criteria->join = ' INNER JOIN table2 ON t.command_id = table2.command_id';
$result = Table_1_class::model()->with('command')->findAll();
$history_data = CJSON::encode($result);
echo $history_data;
}
here command_id is common in table1 and table2.
This is how I am using the criteria code.
As I said, Yii's Active Record implementation will only use columns which are defined in the table itself or the tables you are linking to through with, not arbitrary columns you return in the resultset.
Solution 1: Define a relation to table2, add that relation to with, and get rid of join. Then you'll probably need to convert each returned object to an array - CJSON::encode will not handle a model with relations well.
Solution 2: Use Yii::app()->db->createCommand("SQL query")->queryAll(); instead of Active Record. This will produce an array of arrays, which CJSON::encode will have no problem with.

Many to many relationship on advanced search

I created 3 tables:
User
User-Group
Group
Where I can have a many-to-many relationship.
But how I create on the search method a find to it?
How can I get all users that have a specific group, like
select u.* from users as u, user-group as ug, group as g
where g.name = "group_1" and ug.group_id = g.id and ug.user_id = u.id ?
My code so far:
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'group'=>array(self::MANY_MANY, 'Group', 'tbl_profile(id_user, id_group)'),
'groupList' => array( self::HAS_MANY, 'Group', 'id_user' ),
}
$criteria->with=array('groupList' => array(
'condition' => 'id_user = 1',
));
I would start with the steps in this wiki article:
http://www.yiiframework.com/wiki/281/searching-and-sorting-by-related-model-in-cgridview/
Then, you'd need to add your join table groupID column to your gridviewand user search criterias. You will probably also need to add a with and together=true line to your search criteria.
Note that he has you add a new model attribute to your model to hold the search criteria. If you are using a drop down filter, you can specify your join table attributes' name directly.
User::model()->with(array(
'group'=>array(
'alias'=>'g',
'condition'=>'g.name=:gName',
'params'=>array(':gName'=>'group_1')
)
))->findAll();
or
$crit = new CDbCriteria();
$crit->alias = 'g';
$crit->addColumnCondition(array('g.name'=>'group_1'));
User::model()->with(array('group'=>$crit))->findAll();
or
$crit = new CDbCriteria();
$crit->with = array(
'group'=>array(
'alias'=>'g',
'condition'=>'g.name=:gName',
'params'=>array(':gName'=>'group_1')
)
);
User::model()->findAll($crit);
or
$crit1 = new CDbCriteria();
$crit1->alias = 'g';
$crit1->addColumnCondition(array('g.name'=>'group_1'));
$crit2 = new CDbCriteria();
$crit2->with = array('group'=>$crit1);
User::model()->findAll($crit2);
How i get all users that have a specific group?
select u.* from group g
join user-group ug on g.id = ug.group_id
join users u on u.id = ug.user_id
where g.name = "group_1"

Categories