Double Join Select - yii

Three tables Project, Users, Issues.
Project table columns: p_id,name,...
Users table columns: u_id username...
Issues table columns: i_id i_name...
Relations:
Project has many Users - 1..*
Project has many Users - 1..*
Project has many Issues - 1..*
Users has many Issues - 1..*
What I want to do:
In Yii framework logic: Select Project with all it's users, these users has to have only Issues of the selected Project.
In tables logic: Select Issues of certain project AND user.
What sql code I want to mimic:
SELECT Issue.i_name FROM Issue Join Project on Issue.i_id =
Project.p_id Join User on Issue.i_id User.u_id
What I want to do in Yii:
//get Project
$model = Project::model()->findByPk( $p_id );
//get Project's users
$users = $model->users;
//get each of users issues of selected project
foreach( $users as $user )
$issues = $user->issues;

To solve this you have to use through in your ralations method.
Project model relations method should look like this:
public function relations()
{
return array(
'users' => array(self::MANY_MANY, 'User', 'tbl_project_user_assignment(project_id, user_id)'),
//'issues' => array(self::HAS_MANY, 'Issue', 'project_id'),
'issues' => array(self::HAS_MANY,'Issue',array('id'=>'owner_id'),'through'=>'users'),
'columns' => array(self::MANY_MANY, 'Column', 'tbl_project_rel_column(p_id,c_id)'),
);
}
Now in action select project, it's users and users's posts(or in my case issues) of selected project:
$project = Project::model()->with('users','issues')->findByPk(1);
$users = $project->users;
foreach($users as $user) {
echo $user->username."<br/>";
}
$issues = $project->issues;
foreach($issues as $issue) {
echo $issue->name."<br/>";
}

Related

Yii 1.1 relationship search issue

1. Table meeting
Model name CoreMeeting
Fields id, title, start time, created_by
Relationship:
'MeetingParticipants' => array(self::HAS_MANY, 'MeetingParticipants', 'meeting_id'),
2. Table core_meeting_participant
Model name is meeting_participant
Fields are id, meeting_id, participant_id, group_id
Relationship:
'meeting' => array(self::BELONGS_TO, 'CoreMeeting', 'meeting_id'),
'group' => array(self::BELONGS_TO, 'MeetingGroup', 'group_id'),
3. Table core_meeting_group
Model name is MeetingGroup
Fields are id, group_name
My search filter in the meeting model is:
public function search()
{
$group=filter_var($_REQUEST['group'], FILTER_SANITIZE_STRING);//contain group name
$criteria=new CDbCriteria;
$user_id = Yii::app()->user->id;
$criteria->compare('id',$this->id);
$criteria->compare('title',$this->title,true);
$criteria->with=array('MeetingParticipants'=>array("select"=>"*"),'MeetingParticipants.group'=>array('select'=>'id,group_name'));
if(isset($this->start_time) && !empty($this->start_time))
$criteria->compare('start_time',date("Y-m-d", strtotime($this->start_time)), true);
$criteria->compare('created_by',$user_id);
if(isset($group)&&!empty($group))
$criteria->compare('group.group_name',$group);
$criteria->together = true;
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
I have created 4 meetings, each meeting have at least 5 participants each participant belongs to a meeting group. I want to list all meetings with the following filed meeting title, groups and meeting time.
My problem is if I enable $criteria->together = true; if the meeting has more than 10 participants that will show only 1 meeting in grid view. If I disable this that will show all but I can't search with the meeting name.
SQL fiddle link is http://sqlfiddle.com/#!9/fdaacf
full SQL dump https://pastebin.com/NtpMuCpE
Documentation for CDbCriteria->together property:
https://www.yiiframework.com/doc/api/1.1/CDbCriteria#together-detail
Whether the foreign tables should be joined with the primary table in a single SQL. This property is only used in relational AR queries for HAS_MANY and MANY_MANY relations.
As I can see your relation in CoreMeeting model:
'group' => array(self::BELONGS_TO, 'MeetingGroup', 'group_id')
Obviously you are trying to fetch one-to-one (BELONGS_TO) relation CoreMeeting -> MeetingGroup eagerly by globally setting to your CDbCriteria->together = true; which is not correct according to the documentation.
What I would suggest you, first of all get rid of this global together setting to CDbCriteria and try changing your with clause like this:
$criteria->with = [
// this is your has-many relation (one meeting has several participants), thus we set here `together` to true
'MeetingParticipants' => [
'together' => true,
'with' => [
// this is your one-to-one relation (one participant has one group)
'group'
]
]
];

Left Join CakePHP3

I'm trying to do a LEFT JOIN in CakePHP3.
But all I get is a "is not associated"-Error.
I've two tables BORROWERS and IDENTITIES.
In SQL this is what I want:
SELECT
identities.id
FROM
identities
LEFT JOIN borrowers ON borrowers.id = identities.id
WHERE
borrowers.id IS NULL;
I guess this is what I need:
$var = $identities->find()->select(['identities.id'])->leftJoinWith('Borrowers',
function ($q) {
return $q->where(['borrowers.id' => 'identities.id']);
});
But I'm getting "Identities is not associated with Borrowers".
I also added this to my Identities Table:
$this->belongsTo('Borrowers', [
'foreignKey' => 'id'
]);
What else do I need?
Thanx!
The foreign key cannot just be 'id', that's not a correct model association. You'd need to put a 'borrower_id' field in identities, and declare it like this in the Identities model:
class Identities extends AppModel {
var $name = 'Identities';
public $belongsTo = array(
'Borrower' => array (
'className' => 'Borrower',
'foreignKey' => 'borrower_id'
)
);
Note the capitalization and singular/plural general naming conventions which your example doesn't follow in the least - ignoring those will get you some really hard to debug errors..
Yup. It was an instance of \Cake\ORM\Table, due to my not well chosen table name (Identity/Identities). I guess it's always better not to choose those obstacles, for now I renamed it to Label/Labels.
This query now works perfectly:
$var = $identities
->find('list')
->select(['labels.id'])
->from('labels')
->leftJoinWith('Borrowers')
->where(function ($q) {
return $q->isNull('borrowers.id');
});

Yii with join using CDbCriteria and CActiveDataProvider with custom Search

Hi I am using Yii to create an Application
I have modified the search() in model and I have come up with a problem.
Users can log in as admins, managers, clients
When a user is logged as a manager, he can view clients only from the store they both belong. So far so good, I've managed to accomplish that.
Now the problem is when I try to prevent managers from viewing other managers from the same store (and therefore edit each other's accounts) in CGridView.
The relations
/**
* #return array relational rules.
*/
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(
'authitems' => array(self::MANY_MANY, 'Authassignment', 'authassignment(userid, itemname)'),
'additionalContacts' => array(self::HAS_MANY, 'AdditionalContact', 'Client_Id'),
'store' => array(self::BELONGS_TO, 'Store', 'Store_Id'),
'user' => array(self::BELONGS_TO, 'User', 'User_Id'),
'genericPoints' => array(self::HAS_MANY, 'GenericPoint', 'Client_Id'),
);
}
The Custom model search
public function searchCustom()
{
// Warning: Please modify the following code to remove attributes that
// should not be searched.
$criteria=new CDbCriteria;
$criteria->addCondition('t.id !='.$this->id);
$criteria->compare('t.Created',$this->Created,true);
$criteria->compare('t.Updated',$this->Updated,true);
$criteria->compare('t.Discount',$this->Discount,true);
$criteria->compare('t.Discount_Type',$this->Discount_Type,true);
$criteria->addCondition('t.Store_Id ='.$this->Store_Id);
//$criteria->addCondition('t.id !='.$this->id);
//GET FIELDS FROM USER IN SEARCH
$criteria->with=array('user');
$criteria->compare('user.id',$this->User_Id,true);
$criteria->compare('user.First_Name',$this->First_Name,true);
$criteria->compare('user.Last_Name',$this->Last_Name,true);
$criteria->compare('user.Username',$this->Username,true);
$criteria->compare('user.Email',$this->Email,true);
$criteria->addCondition('user.Status = 1');
$criteria->with=array('authitems');
$criteria->compare('authitems.userid',$this->id,false);
$criteria->compare('authitems.itemname','client',false);
$criteria->together = true;
$criteria->order = 't.Created DESC';
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
And this the error I am getting
CDbCommand failed to execute the SQL statement: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'user.Status' in 'where clause'. The SQL statement executed was: SELECT COUNT(DISTINCT `t`.`id`) FROM `client` `t` LEFT OUTER JOIN `authassignment` `authitems_authitems` ON (`t`.`id`=`authitems_authitems`.`userid`) LEFT OUTER JOIN `authassignment` `authitems` ON (`authitems`.`itemname`=`authitems_authitems`.`itemname`) WHERE (((((t.id !=2) AND (t.Store_Id =1)) AND (user.Status = 1)) AND (authitems.userid=:ycp0)) AND (authitems.itemname=:ycp1))
I know it has something to do with the relations the gii set up for me but I can't pinpoint it.
Perhaps authitems' MANY_MANY relation stops the user relation from loading?
Instead of making another assignement for $criteria->with (which will override the previous one), you should simply try :
$criteria->with=array('user', 'authitems');

solution for Insert Data In Relation Table by yii FW

I want do a project with YiiFramework.
in this project I have 1 table that have many relation
I want create a form that insert data in main table and all relation
for example :
I want a form that add student information
I have 2 table
first : id name family
and
second: id student_id field
I want add data in table 1 and then add data in table 2
and all of the this jobs do in a form
do u have any solution for that?
my really reations :
'homehouse' => array(self::HAS_ONE, 'Homehouse', 'HouseId'),
'houseType' => array(self::BELONGS_TO, 'Parametervalues', 'HouseTypeId'),
'owner' => array(self::BELONGS_TO, 'Person', 'OwnerId'),
'region' => array(self::BELONGS_TO, 'Region', 'RegionId'),
'housemultimedias' => array(self::HAS_MANY, 'Housemultimedia', 'HouseId'),
'housestages' => array(self::HAS_MANY, 'Housestage', 'HouseId'),
'tradehouse' => array(self::HAS_ONE, 'Tradehouse', 'HouseId'),
You have to do it with each model, so, let's say you have 2 models (student and job) and you're sending the data from the form with POST method.
Them, in your controller, you save first the main data and second the relation, for example: (ps. this is just a hypothetical example)
Controller
public function actionSave(){
if(isset($_POST['Student'])) {
$Student = new Student();
$Student->Job = new Job();
$Student->attributes = $_POST['Student'];
$Student->Job->attributes = $_POST['Job'];
if($Student->save()){
$Student->Job->student_id = $Student->id;
$Student->Job->save();
}
}
}
With this idea, you can save the data in many relations that you model has.
Reference: How to save related objects?

Active Record- How to select a column with relationship?

Projects can have unlimited number of columns (to form a table or something), relationship MANY to MANY. To implement this tbl_project_rel_column is created. It stores project_id, column_id AND pos position of column in Project table.
I am using AC database approach. I have 2 models Project and Column.
Project model's relations method:
public function relations(){
return array(
...
'columns'=>array(self::MANY_MANY,'Column','tbl_project_rel_column('p_id','c_id')
);
}
Now can get all project's columns using something like this:
$model = Project::model()->findbyPk($p_id);
$columns = $model->columns;
But column doesn't store 'pos'(position) value of it's certain project.
How to get 'pos' value of tpl_project_rel_column table of certain project and certain column?
You can use the through feature instead of MANY_MANY. It may also be useful to index the results by the position column. Try something like this:
public function relations()
{
return array(
'projectColumns' => array(self::HAS_MANY, 'ProjectRelColumn', 'p_id', 'index'=>'position'),
'columns' => array(self::HAS_MANY, 'Column', 'c_id', 'through'=>'projectColumns'),
}
Now you can query for projects with columns like this:
$projects = Project::model()->with('columns')->findAll();
foreach($projects as $project) {
// projectColumns are indexed by position. You can sort by this now:
ksort($project->projectColumns)
foreach($project->projectColumns as $pos => $projectColumn)
echo "Pos: $pos Column: {$projectColumn->column->name}";
}