Yii CDbCriteria Join - php

How I can write the query
SELECT *
FROM doc_docs dd
JOIN doc_access da
ON dd.id=da.doc_id
AND da.user_id=7
with CDbCriteria syntax?

You actually cant completely write that since you have to apply the criteria to an activerecord model to obtain the primary table, but assuming you have a DocDocs model you can do it like this:
$oDBC = new CDbCriteria();
$oDBC->join = 'LEFT JOIN doc_access a ON t.id = a.doc_id and a.user_id = 7';
$aRecords = DocDocs::model()->findAll($oDBC);
Although it might be a lot easier if you give your DocDocs model a relation with doc_access, then you don't have to use the dbcriteria:
class DocDocs extends CActiveRecord
{
...
public function relations()
{
return array('access' => array(self::HAS_MANY, 'DocAccess', 'doc_id');
}
...
}
$oDocDocs = new DocDocs;
$oDocDocs->id = 7;
$aRecords = $oDocDocs->access;
Should give you a fairly good idea how to start...

Related

Return ORM object and convert SQL to Doctrine QueryBuilder syntax

I'm creating a function that should return an array of User ORM object. The function should run a query to the DB and return the users where the users' contact persons has 1 company (not more or less). The relationship is like this: every user has one or more contact person and every contact person has one or more companies.
The SQL to locate these users are like this. We are using PHP 7.1, Symfony 3.4 and Doctrine 2.7.
The problem that I have is that I cannot manage to describe this in Doctrine QueryBuilder syntax so that an array of User ORM objects are returned. Can anybody give me some advice?
SELECT users.email
FROM company
INNER JOIN contact_person ON contact_person.id = company.belongs_to_contact_person_id
INNER JOIN users ON users.id = contact_person.belongs_to_user_id
GROUP BY users.email
HAVING COUNT(company.id) = 1
Depending on how your mapping is on your entities, you have multiple solution.
It would be nice if you can show us what you tried so we can see what you miss.
The best is to use the repository of the entity you whish to have an array of:
namespace App\Repository;
use App\Entity\User;
use Doctrine\ORM\EntityRepository;
class UserRepository extends EntityRepository
{
/**
* #return User[]
*/
public function findUsersHavingAtLeastOneCompany():array
{
return $this->createQueryBuilder('user')
->join('user.contact', 'contact')
->join('contact.company', 'company')
->where('contact.company = 1')
->getQuery()
->getResult();
}
}
When using the createQueryBuilder function, it will auto populate the select and the from.
The getResult will return an array of entity (if you have not defined a select)
I fixed this by using the following code using createNativeQuery. It can probably be done by using fever lines of code, but it does the job for me :)
$em = $this->getEntityManager();
$sql = <<<SQL
SELECT users.id
FROM company
INNER JOIN contact_person ON contact_person.id = company.belongs_to_contact_person_id
INNER JOIN users ON users.id = contact_person.belongs_to_user_id
GROUP BY users.id
HAVING COUNT(company.id) = 1
SQL;
$rsm = new ResultSetMapping();
$rsm->addScalarResult('id', 'text');
$query = $em->createNativeQuery($sql, $rsm);
$locatedUsers = [];
foreach ($query->getResult() as $lUser) {
foreach ($lUser as $user) {
$locatedUser = $em->find("Project\User\User", $user);
array_push($locatedUsers, $locatedUser);
}
}
return $locatedUsers;

Yii CDBCriteria LEFT JOIN not working

I have a CDBCriteria here:
$criteria = new CDbCriteria;
$criteria->select = array('t.lastname', 't.name', 't.patronomic', 't.dob', 'n.nationality', 't.token', 'm.status');
$criteria->join = 'LEFT JOIN hrp_nationalities n ON (n.id = t.nationality_id) ';
$criteria->join .= 'LEFT JOIN hrp_marital_status m ON m.id = t.marital_status_id';
$criteria->condition = "t.`alive` = 1 AND t.`org_id` = ".$_SESSION['org_id'];
$criteria->order = 't.id DESC';
My question is why m.status and n.nationality are not retrieved into the resulting object?
If you are using the CDbCriteria on a model class eg $results = User::model()->findAll($criteria); then the result will contain only fields from user table, not the relations'. The reason is that when the resultant model objects are created there is no field declared for the relation columns in the model.. So you need to create fields in the model..
in your case nationality, status
Just write in your model
public $nationality;
public $status;
And if your model also has a field named status, use an alias for the relation's field status..
public $m_status;
$criteria->select = array('t.lastname', 't.name', 't.patronomic', 't.dob', 'n.nationality', 't.token', 'm.status as m_status');
I just remember I have answered an old similar question.. Read answer here: https://stackoverflow.com/a/11594530/1114536

Laravel converting right join to left join

I have been trying to convert a right join query to left join query in order to use it inside laravel query builder. Here is my Sql statement and it result wich works flawlessly
select `weekday`.`name`, `open_time`, `close_time`
from `schedule`
join `restaurants_has_schedule` on `schedule`.`id` = `restaurants_has_schedule`.`schedule_id`
and `restaurants_has_schedule`.`restaurants_id` = 1
right join `weekday` on `weekday`.`id` = `schedule`.`weekday_id`
ORDER BY `weekday`.`id`
|------
|name|open_time|close_time
|------
|Domingo|NULL|NULL
|Lunes|NULL|NULL
|Martes|NULL|NULL
|Miercoles|NULL|NULL
|Jueves|14:11:51|14:11:51
|Vienes|09:11:21|17:00:00
|Sábado|NULL|NULL
but when convert It to left join it stop working, displaying me the same data for every single restaurants_id. This is my left join statement.
select `weekday`.`name`, `open_time`, `close_time`
from `weekday`
left join `schedule` on `weekday`.`id` = `schedule`.`weekday_id`
join `restaurants_has_schedule` on `schedule`.`id` = `restaurants_has_schedule`.`schedule_id`
and `restaurants_has_schedule`.`restaurants_id` = 1
ORDER BY `weekday`.`id`
What am I doing wrong? Is There another alternative? Thak you in advance
Try use Laravels Eloquent ORM, which handles relationships really cool! no need anymore to concat or write sql-queries
See here about: Laravels Eloquent ORM & Schema Builder
Or maybe about orm's in general, you should really give it a try:
Object Role Modeling
Object Role Modeling
Example from Laravel doc:
One Post may have many comments
One to many:
class Post extends Eloquent {
public function comments()
{
return $this->hasMany('Comment');
}
}
Where 'Comment' is the model.
The "reverse" to define:
class Comment extends Eloquent {
public function post()
{
return $this->belongsTo('Post');
}
}
Where 'Post' is the model.
And then as query:
$comments = Post::find(1)->comments; //by Primary Key
Or
$comments = Post::where('somefield', '=', 'somevalue')->comments->get();
....Really cool, for many to many see the docs#Laravels Eloquent ORM

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.

Sub-queries ActiveRecord Yii

Is it possible to make sub-queries in ActiveRecord in Yii?
i have a query like this:
select * from table1
where table1.field1 in (select table2.field2 from table2)
i'm currently using the fallowing code:
object1::model()->findAll(array('condition'=>'t.field1 in (select table2.field2 from table2)'))
[Edit]
i would like to know if there is a manner to construct the sub-query without using SQL, and without using joins.
Is there any solution ?
and thanks in advance.
First find doublets by db fields:
$model=new MyModel('search');
$model->unsetAttributes();
$criteria=new CDbCriteria();
$criteria->select='col1,col2,col3';
$criteria->group = 'col1,col2,col3';
$criteria->having = 'COUNT(col1) > 1 AND COUNT(col2) > 1 AND COUNT(col3) > 1';
Get the subquery:
$subQuery=$model->getCommandBuilder()->createFindCommand($model->getTableSchema(),$criteria)->getText();
Add the subquery condition:
$mainCriteria=new CDbCriteria();
$mainCriteria->condition=' (col1,col2,col3) in ('.$subQuery.') ';
$mainCriteria->order = 'col1,col2,col3';
How to use:
$result = MyModel::model()->findAll($mainCriteria);
Or:
$dataProvider = new CActiveDataProvider('MyModel', array(
'criteria'=>$mainCriteria,
));
Source: http://www.yiiframework.com/wiki/364/using-sub-query-for-doubletts/
No, there is not a way to programmatically construct a subquery using Yii's CDbCriteria and CActiveRecord. It doesn't look like the Query Builder has a way, either.
You can still do subqueries a few different ways, however:
$results = Object1::model()->findAll(array(
'condition'=>'t.field1 in (select table2.field2 from table2)')
);
You can also do a join (which will probably be faster, sub-queries can be slow):
$results = Object1::model()->findAll(array(
'join'=>'JOIN table2 ON t.field1 = table2.field2'
);
You can also do a direct SQL query with findAllBySql:
$results = Object1::model()->findAllBySql('
select * from table1 where table1.field1 in
(select table2.field2 from table2)'
);
You can, however, at least provide a nice AR style interface to these like so:
class MyModel extends CActiveRecord {
public function getResults() {
return Object1::model()->findAll(array(
'condition'=>'t.field1 in (select table2.field2 from table2)')
);
}
}
Called like so:
$model = new MyModel();
$results = $model->results;
One interesting alternative idea would be to create your subquery using the Query Builder's CDbCommand or something, and then just pass the resulting SQL query string into a CDbCritera addInCondition()? Not sure if this will work, but it might:
$sql = Yii::app()->db->createCommand()
->select('*')
->from('tbl_user')
->text;
$criteria->addInCondition('columnName',$sql);
You can always extend the base CDbCriteria class to process and build subqueries somehow as well. Might make a nice extension you could release! :)
I hope that helps!
I know this an old thread but maybe someone (like me) still needs an answer.
There is a small issues related to the previous answers. So, here is my enhancement:
$model=new SomeModel();
$criteria=new CDbCriteria();
$criteria->compare('attribute', $value);
$criteria->addCondition($condition);
// ... etc
$subQuery=$model->getCommandBuilder()->createFindCommand($model->getTableSchema(),$criteria)->getText();
$mainCriteria=new CDbCriteria();
$mainCriteria->addCondition($anotherCondition);
// ... etc
// NOW THIS IS IMPORTANT
$mainCriteria->params = array_merge($criteria->params, $mainCriteria->params);
// Now You can pass the criteria:
$result = OtherModel::model()->findAll($mainCriteria);

Categories