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();
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 would like to query the database for
Plates.page_number => 1 OR Plates.page_number => Cover
I am attempting to use the following code, but I am not getting the results I am looking for because of a duplicate array key, how can I search the same field for two different values?
$query = $this->Ledgers->find('all', array(
'contain' => array(
'Plates' => [
'conditions' => [
'OR' => [
'Plates.plate_title' => 'Front Cover',
'Plates.page_number' => '1',
'Plates.page_number' => 'Cover' // Duplicate Array Key
]
]
], 'Plates.PlateImages', 'Tribes'
),
'conditions' => array(
'Ledgers.disabled' => 'n', 'Ledgers.id IN' => $ledgerIds
)
))->orderAsc('ledger_title');
Please try wrapping your conditions in separate arrays, eg:
'OR' => [
['Plates.page_number' => '1'],
['Plates.page_number' => 'cover'],
...
]
More info can be found in CakePHP docs:
Query Builder -> Advanced Conditions
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.
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']
];
Order HasOne Suborder
Suborder BelongsTo Order
I need to sort Orders by a field in Suborders, but sorting by virtual fields appears to have been removed in Cake 3.x
In OrdersTable.php, I have
$this->hasOne('Suborder', [
'className' => 'Suborders',
'foreignKey' => 'order_id',
'strategy' => 'select',
'conditions' => function ($exp, $query) {
return $exp->add(['Suborder.id' => $query
->connection()
->newQuery()
->select(['SSO.id'])
->from(['SSO' => 'suborders'])
->where([
'Suborder.order_id = SSO.order_id',
'SSO.suborder_type_id in' => [1, 2, 3]
])
->order(['SSO.id' => 'DESC'])
->limit(1)]);
}
]);
In OrdersController.php, I have
$this->paginate = [
'limit' => 20,
'order' => ['id' => 'desc'],
'sortWhitelist' => [
'id',
'title',
'client_order',
'substatus',
'Workflows.order_status_id',
'Clients.name',
'ProductTypes.type',
'Suborder.due_date',
'Suborder.created',
],
];
$orders = $this->paginate($collection);
In index.ctp, I have
$this->Paginator->sort('Suborder.created', 'Order Placed'),
$this->Paginator->sort('Suborder.due_date'),
and the error I'm getting is Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Suborder.created' in 'order clause'. How do I get Cake to include the Suborder in the initial query for sorting and pagination?
Edit:
$collection = $this->Orders->find()
->contain([
'Clients',
'CurrentAssignment.Users',
'Workflows.OrderStatuses.Category',
'Workflows.OrderStatuses.Departments' => function ($q) use ($uID) {
return $this->Departments->find()->matching('Users', function ($q) use ($uID) {
return $q->where(['Users.id' => $uID]);
});
},
'ClientProducts.ProductTypes',
'Reviews' => function ($q) {
return $q->where(['review_type_id is not' => 6]);
},
'Reviews.ReviewTypes',
'PublicNotes',
'ActiveReview',
'Suborder',
'Suborder.SuborderTypes',
'Suborders.SuborderTypes',
]);
and $collection is modified with 150 lines of wheres, orWheres, and joins based on a number of conditions.
You have configured the assocaition to use the select strategy, which will use a separate query to retrieve the data (currently wrongly documented), hence you cannot reference it in the main query used for pagination.
So you have to use the default join strategy instead if you want to sort on it.
See also
Cookbook > Database Access & ORM > Associations - Linking Tables Together > HasOne Associations