We have 4 tables
Users
-id
Profiles
-id
-user_id
Questions
-id
Options
-id
ProfileQuestions
-id
-profile_id
-question_id
-option_id
Now i require to get all profiles and each profile have multiple questions and each question has many options.
User Model
$this->hasMany('Profiles', [
'foreignKey' => 'user_id'
]);
Profiles Model
$this->belongsToMany('Questions', [
'foreignKey' => 'profile_id',
'targetForeignKey' => 'question_id',
'joinTable' => 'profile_questions',
'through' => 'ProfileQuestions' ,
'joinType' => 'LEFT']);
Questions Model
$this->belongsToMany('Options', [
'foreignKey' => ['question_id'],
'targetForeignKey' => 'option_id',
'joinTable' => 'profile_questions',
'through' => 'ProfileQuestions'
]);
ProfileQuestions Model
$this->belongsTo('Profile', [
'foreignKey' => 'profile_id',
]);
$this->belongsTo('Questions', [
'foreignKey' => 'question_id'
]);
$this->belongsTo('Options', [
'foreignKey' => 'option_id'
]);
Controller code to get the result
$query = $this->Users->find('first')
$query->contain(['Profiles.Questions.Options']);
Error
Fatal error: Out of memory (allocated 408944640) (tried to allocate 665912212 bytes) in vendor\cakephp\cakephp\src\Database\Statement\MysqlStatement.php on line 39
Issue is related to Associations. If we set the profile_id where condition with the options contain then it works for that profile id.
Related
I have created a table called Delegates, and I created a UsersTable and User Entity. And I have used $this->setTable('delegates'); in UsersTable to be able to access Delegates from $this->Users; (I just want to say I have created a User Model with delegates table)
So far so good...
In my application I am trying to access deep associations. Every thing is fine with this query but when I contain the User model I get The Users association is not defined on Comments.
I can confirm the associations are set correctly.
...
// There are more associations up there.
...
'Comments', [
'className' => 'App\Model\Table\CommentsTable',
'foreignKey' => 'delegate_assessment_criteria_id',
'belongsTo' => [
'Assessors' => [
'className' => 'App\Model\Table\AssessorsTable',
'foreignKey' => 'assessor_id',
],
'Users' => [
'className' => 'App\Model\Table\UsersTable',
'foreignKey' => 'delegate_id',
]
]
]
Here is deep association.
...
// There are more associations up there.
...
'Comments' => function($q) {
return $q
->select([
'id'
])
->order(['Comments.created DESC'])
->contain([
'Assessors' => function($q) {
return $q
->select([
'id'
])
->enableAutoFields();
}
])
->contain([
'Users' => function($q) {
return $q
->select([
'id',
'delegate_id'
])
->enableAutoFields();
}
])
->enableAutoFields();
}
2 Notes:
If I contain the User model in very first in hierarchy of my query I
can access the User fields but in deep association this doesn't
work.
If I contain Delegates it works.
I believe there is a problem with Cakephp query builder.
Alright finally I figured it out. I have done it before I don't know why I forgot. Probably because I was in deep association I drained into it.
The deep association contain was creating conflict with very first contain. if I would set different propertyName in deep associations then it does the purpose.
Bear in mind you must set this associations on your Table Models.
'Comments', [
'className' => 'App\Model\Table\CommentsTable',
'foreignKey' => 'delegate_assessment_criteria_id',
'belongsTo' => [
'Assessors' => [
'className' => 'App\Model\Table\AssessorsTable',
'foreignKey' => 'assessor_id',
],
'Delegates' => [ // <= Here set the name of Assossiation you want to be shown in array
'className' => 'App\Model\Table\UsersTable',
'propertyName' => 'delegates', // <= Add propertyName and set another name here
'foreignKey' => 'delegate_id',
]
]
]
And on association
'Comments' => function($q) {
return $q
->select([
'id'
])
->order(['Comments.created DESC'])
->contain([
'Assessors' => function($q) {
return $q
->select([
'id'
])
->enableAutoFields();
}
])
->contain([
'Users' => function($q) {
return $q
->select([
'id',
// 'delegate_id' // <= Remove this - We have already done it when we set the association on above code.
])
->enableAutoFields();
}
])
->enableAutoFields();
}
I dont understand from the docs why I cant retrieve selected fields from associated data.
I have 2 many to many relationships in the contain which displays everything fine.
$query3 = $this->find()
->contain(['Subjects','AvailabilityForStudents'])
->select([
'Students.id','Students.first_name','Students.last_name','Students.address_billing','Students.address_lat','Students.address_long',
'Students.class_year','Students.address_street','Students.address_suburb','Students.address_postcode','Students.address_state'])
->where(['Students.id IN' => $stids])
->order(['Students.first_name' => 'ASC'])
->hydrate(true);
My Question is that instead of getting every field from the contained models why cant I select fields from the contained model as below? I am not selecting based on a criteria like in matching clause?
$query3 = $this->find()
->contain(['Subjects','AvailabilityForStudents'])
->select(['Subjects.name','Subjects.id','AvailabilityForStudents.id',
'Students.id','Students.first_name','Students.last_name','Students.address_billing','Students.address_lat','Students.address_long',
'Students.class_year','Students.address_street','Students.address_suburb','Students.address_postcode','Students.address_state'])
->where(['Students.id IN' => $stids])
->order(['Students.first_name' => 'ASC'])
->hydrate(true);
//student model
$this->hasMany('AvailabilityForStudents', [
'className' => 'AvailabilityForStudents',
'foreignKey' => 'student_id',
'dependent' => false,
]);
$this->belongsToMany('Subjects', [
'foreignKey' => 'student_id',
'targetForeignKey' => 'subject_id',
'joinTable' => 'subjects_students'
]);
//update contain
$query3 = $this->find()
->contain([
'Subjects'=>['fields'=>['name','id','SubjectsStudents.student_id']],
'AvailabilityForStudents' ])
// ->contain(['Subjects','AvailabilityForStudents'])
->where(['Students.student_unallocated' => 1,'Students.student_inactive' => 0])
->order(['Students.first_name' => 'ASC'])
->hydrate(true);
https://book.cakephp.org/3.0/en/orm/retrieving-data-and-resultsets.html
You are doing right.
You can try this also,
$query3 = $this->find()
->contain([
'Subjects'=>['fields'=>['name','id','SubjectsStudents.student_id']],
'AvailabilityForStudents'=>['fields'=>'id']
])
->select(['Students.id','Students.first_name','Students.last_name','Students.address_billing','Students.address_lat','Students.address_long',
'Students.class_year','Students.address_street','Students.address_suburb','Students.address_postcode','Students.address_state'])
->where(['Students.id IN' => $stids])
->order(['Students.first_name' => 'ASC'])
->hydrate(false)->toArray();
I have a table name countries , countries has relation with users, users has relation with MoneyTransferTransactions
In MoneyTransferTransactions view I need fetch country name.
I already join Users table in MoneyTransferTransactionsTable by below code
$this->belongsTo('Users', [
'foreignKey' => 'user_id',
'joinType' => 'INNER'
]);
In user table I also used inner join like below code
$this->belongsTo('Countries', [
'foreignKey' => 'country_id',
'joinType' => 'INNER'
]);
In MoneyTransferTransactions controller I have used below code to fetch all data with associated data.
$this->paginate = [
'contain' => ['Users','TransferOptions'],
'conditions'=> ['MoneyTransferTransactions.status'=>1],
'order' =>['MoneyTransferTransactions.id'=>'DESC']
];
I have used var_dump in index.ctp , I gotted country id from users table but not got country name from countries table. How can I get country name from MoneyTransferTransactions>index.ctp ?
Add association between Users and Countries in 'contain'
$this->paginate = [
'contain' => ['TransferOptions', 'Users' => ['Countries']],
'conditions' => ['MoneyTransferTransactions.status' => 1],
'order' => ['MoneyTransferTransactions.id' => 'DESC']
];
We have 3 tables - items, locations and taxes. items_locations and locations_taxes are already associated. But, there is a need to connect all of them - items_locations_taxes
Database schema is already in place. When I baked locations model, it did something like this :
$this->belongsToMany('LocationsTaxes', [
'foreignKey' => 'location_id',
'targetForeignKey' => 'locations_tax_id',
'joinTable' => 'items_locations_taxes'
]);
$this->belongsToMany('Items', [
'foreignKey' => 'location_id',
'targetForeignKey' => 'item_id',
'joinTable' => 'items_locations'
]);
$this->belongsToMany('Taxes', [
'foreignKey' => 'location_id',
'targetForeignKey' => 'tax_id',
'joinTable' => 'locations_taxes'
]);
First belongsToMany seems to be wrong. Its auto generated through Bake.
Now, how can these 3 be connected through join?
And, take a note that junction tables are using composite primary keys and do not contain id column.
In user model:
var $hasMany = array(
'Photo' => array(
'className' => 'Photo',
'foreignKey' => 'owner_id',
...
),
);
In photo model:
var $belongsTo = array(
'Owner' => array(
'className' => 'User',
'foreignKey' => 'owner_id',
...
),
);
Here one user has many photos.
So what my question is that here the alias name is 'Owner', which make me clear to understand the exact meaning of 'User', but is this the only reason to use alias? does it affect 'Photo' in user model? or how to use 'Owner' in/by cakephp?
I don't quite understand the meaning of alias in model.
Appreciate your help!
Two useful scenarios for aliases:
1. Multiple foreign keys to the same model
For example, your photos table has two fields: created_user_id & modified_user_id
var $belongsTo = array(
'CreatedUser' => array(
'className' => 'User',
'foreignKey' => 'created_user_id',
...
),
'ModifiedUser' => array(
'className' => 'User',
'foreignKey' => 'modified_user_id',
...
),
);
2. Creating logical words specific to your application's domain
Using the conditions field in the array, you could specify different kinds of models:
var $hasMany = array(
'ApprovedUser' => array(
'className' => 'User',
'foreignKey' => 'group_id',
'conditions' => array(
'User.approved' => 1,
'User.deleted' => 0
),
...
),
'UnapprovedUser' => array(
'className' => 'User',
'foreignKey' => 'group_id',
'conditions' => array(
'User.approved' => 0,
'User.deleted' => 0
),
...
),
'DeletedUser' => array(
'className' => 'User',
'foreignKey' => 'group_id',
'conditions' => array('User.deleted' => 1),
...
),
);
In the above example, a Group model has different kinds of users (approved, unapproved and deleted). Using aliases helps make your code very elegant.
It allows you to do things like $this->Owner->read(null,$userId); You can have an OwnersController and views/owners.
It is ... an alias. In a sense, User is an alias for the db table users.
A better example: I have a CMS where I use the table articles for Article, BlogItem and News. Those three names are aliases for the same table that allow me to set up different models, relationships and behaviour. So I have a BlogItemsController and a NewsController as well as an ArticlesController.