CakePHP: formatResults() and combine() - cakephp

Suppose I have this find():
$categories = $this->Pages->Categories->find('active')
->select(['title', 'slug', 'page_count'])
->order(['title' => 'ASC'])
->cache('widget_categories')
->toArray();
Now, I want the slug field will be the array key.
For now I use a (horrible) loop:
foreach ($categories as $k => $category) {
$categories[$category->slug] = $category;
unset($categories[$k]);
}
Example of debug for $categories:
########## DEBUG ##########
[
'first-page-category' => object(MeCms\Model\Entity\PagesCategory) {
'title' => 'First page category',
'slug' => 'first-page-category',
'page_count' => (int) 1,
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'MeCms.Categories'
},
'sub-sub-page-category' => object(MeCms\Model\Entity\PagesCategory) {
'title' => 'Sub sub page category',
'slug' => 'sub-sub-page-category',
'page_count' => (int) 2,
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'MeCms.Categories'
}
]
###########################
This creates two problems:
it's a horrible method;
the data is cached before changing the array keys, then the same cycle must be performed each time.
One possible solution is to use Cache::read() and Cache::write(). Example:
$categories = Cache::read('widget_categories');
if (empty($categories)) {
//Find...
//Loop for changing keys...
Cache::write('widget_categories', $categories);
}
What seems to me the best solution, however, it is to use formatResults() with combine() methods. Example:
$categories = $this->Pages->Categories->find('active')
->select(['title', 'slug', 'page_count'])
->order(['title' => 'ASC'])
->formatResults(function ($results) {
return $results->combine('slug', function ($row) {
return $row;
});
})
->cache('widget_categories')
->toArray();
It's correct? Is there a simpler method and/or makes the code more readable?
Thanks.

Related

How to create a self BelongsToMany relation in CakePHP 3

I have a database with a table "projekte" (german word for projects).
Some of the projects have a relation to eachother.
So i would like to have a BTM relation.
I created a joinTable "projektverbindungen" with the following fields:
projekt_id
nebenprojekt_id
I found a similar question here: BelongstoMany relationship between a table and itself and i tried the answer of ndm, but without success.
Here is my ProjekteTable.php
class ProjekteTable extends Table {
public function initialize(array $config)
{
parent::initialize($config);
$this->setTable('projekte');
$this->setDisplayField('name');
$this->setPrimaryKey('id');
$this->hasOne('Projekteigenschaften', [
'foreignKey' => 'projekt_id',
'dependent' => true,
]);
$this->belongsToMany('Projekte', [
'foreignKey' => 'projekt_id',
'targetForeignKey' => 'nebenprojekt_id',
'joinTable' => 'projektverbindungen',
]);
}
}
Here ist my template (add.ctp)
<?php
echo $this->Form->create($projekt);
echo $this->Form->control('name', ['class' => 'form-control']);
echo $this->Form->control('projekteigenschaft.projektverantwortlich');
echo $this->Form->control('projekteigenschaft.beschreibung');
echo $this->Form->control('projekte._ids', ['options' => $projekte, 'multiple' => true]);
echo $this->Form->button(__('Submit'));
echo $this->Form->end();
?>
The first step, saving a project with a related project works as expected.
The id of the created project was saved as projektverbindungen.projekt_id and the id of the related project as projektverbindungen.nebenprojekt_id.
When i query a projekt without the relation to other projects like so:
$projekt = $this->Projekte->get($id, [
'contain' => ['Projekteigenschaften']
]);
the query looks like this:
SELECT Projekte.id AS `Projekte__id`, Projekte.name AS `Projekte__name`, Projekteigenschaften.id AS `Projekteigenschaften__id`, Projekteigenschaften.projektverantwortlich AS `Projekteigenschaften__projektverantwortlich`, Projekteigenschaften.beschreibung AS `Projekteigenschaften__beschreibung`, Projekteigenschaften.projekt_id AS `Projekteigenschaften__projekt_id` FROM projekte Projekte LEFT JOIN projekteigenschaften Projekteigenschaften ON Projekte.id = (Projekteigenschaften.projekt_id) WHERE (Projekte.id = :c0 AND (Projekte.deleted) IS NULL)
And the debug of the result looks like:
"id": "6862279f-8134-401f-86ff-9278a3bfa5c3",
"name": "My Project",
"projekteigenschaft": {
"id": "89d9e241-e700-4c31-9266-ee5717f2a0aa",
"projektverantwortlich": "Blisginnis, Ralf",
"beschreibung": ""
}
Everything works fine.
But when i add the projects to contain like so:
$projekt = $this->Projekte->get($id, [
'contain' => ['Projekteigenschaften', 'Projekte']
]);
The query looks the same like above, but the entity looks a bit different:
"Projekteigenschaften": {
"id": "89d9e241-e700-4c31-9266-ee5717f2a0aa",
"projektverantwortlich": "Blisginnis, Ralf",
"beschreibung": ""
}
Projekteigenschaften seems no longer to be a hasOne relation and "Projekte" gets totally ignored.
Anyone has an idea what i did wrong? Or should i prefer an other way of doing this?
edit after ndm´s comment
I tried defining the relationship like so:
$this->belongsToMany('Projektverbindungen', [
'class' => 'Projekte',
'foreignKey' => 'projekt_id',
'targetForeignKey' => 'nebenprojekt_id',
'joinTable' => 'projektverbindungen',
]);
and changed the add.ctp template like so:
echo $this->Form->control('projektverbindungen._ids', ['options' => $projekte, 'multiple' => true]);
But then it doesn´t save the relation.
I also tried to rename the joinTable to projekte_projekte. It didn´t seem to make any difference.
Then I tried to use the through-option, but the results of that were even worse.
So I continued trying to find a solution with the method described above.
2nd edit
projekverbindungen ist accessible in Projekt.php:
protected $_accessible = [
'name' => true,
'projekteigenschaft' => true,
'projekte' => true,
'projektverbindungen' => true,
];
Debug of requestData:
[
'name' => 'My Project',
'projekteigenschaft' => [
'projektverantwortlich' => 'John Doe',
'beschreibung' => '',
'projektverbindungen' => [
'_ids' => [
(int) 0 => '809031f2-4ecd-4dfb-82d5-2c911286dd21'
]
]
]
Debug of entity after patching:
object(App\Model\Entity\Projekt) {
'name' => 'My Project',
'projekteigenschaft' => object(App\Model\Entity\Projekteigenschaft) {
'projektverantwortlich' => 'John Doe',
'beschreibung' => '',
'[new]' => true,
'[accessible]' => [
'projektverantwortlich' => true,
'beschreibung' => true,
'projekt_id' => true,
'projekt' => true
],
'[dirty]' => [
'projektverantwortlich' => true,
'beschreibung' => true
],
'[original]' => [],
'[virtual]' => [],
'[hasErrors]' => false,
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Projekteigenschaften'
},
'projektverbindungen' => [],
'[new]' => true,
'[accessible]' => [
'name' => true,
'projekteigenschaft' => true,
'projekte' => true,
'projektverbindungen' => true
],
'[dirty]' => [
'name' => true,
'projekteigenschaft' => true,
'projektverbindungen' => true
],
'[original]' => [],
'[virtual]' => [],
'[hasErrors]' => false,
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Projekte'
}
3rd edit
In my bootstrap.php i have this:
Inflector::rules('plural', [
'/^(projekt)$/i' => '\1e',
'/^(projekteigenschaft|projektverbindung)$/i' => '\1en',
]);
Inflector::rules('singular', [
'/^(projekt)e$/i' => '\1',
'/^(projekteigenschaft|projektverbindung)en$/i' => '\1',
]);
After your recommendation I additionally added propertyName to the definition of the association:
$this->belongsToMany('Projektverbindungen', [
'class' => 'Projekte',
'propertyName' => 'Projektverbindungen',
'foreignKey' => 'projekt_id',
'targetForeignKey' => 'nebenprojekt_id',
'joinTable' => 'projektverbindungen',
]);
After that, the patched entity looks like this:
object(App\Model\Entity\Projekt) {
'name' => 'My Project',
'projekteigenschaft' => object(App\Model\Entity\Projekteigenschaft) {
'projektverantwortlich' => 'John Doe',
'beschreibung' => '',
'[new]' => true,
'[accessible]' => [
'projektverantwortlich' => true,
'beschreibung' => true,
'projekt_id' => true,
'projekt' => true
],
'[dirty]' => [
'projektverantwortlich' => true,
'beschreibung' => true
],
'[original]' => [],
'[virtual]' => [],
'[hasErrors]' => false,
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Projekteigenschaften'
},
'projektverbindungen' => [
'_ids' => [
(int) 0 => '1e28a3d1-c914-44be-b821-0e87d69cd95f'
]
],
'[new]' => true,
'[accessible]' => [
'name' => true,
'projekteigenschaft' => true,
'projekte' => true,
'projektverbindungen' => true
],
'[dirty]' => [
'name' => true,
'projekteigenschaft' => true,
'projektverbindungen' => true
],
'[original]' => [],
'[virtual]' => [],
'[hasErrors]' => false,
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Projekte'
}
But still no new entry in the table "projektverbindungen"
The last suggestion of ndm made the trick.
Now it works like expected. Thank you very much!
Here is the correct setup:
ProjekteTable.php
$this->belongsToMany('Nebenprojekte', [
'className' => 'Projekte',
'foreignKey' => 'projekt_id',
'targetForeignKey' => 'nebenprojekt_id',
'joinTable' => 'projektverbindungen',
]);
Here I used the property class instead of className, that has been the biggest issue.
Thats really embarrassing, because in the Cookbook is the correct name of that property:
https://book.cakephp.org/3/en/orm/associations.html#belongstomany-associations
Nevertheless, perhaps anyone else makes the same mistake and this thread can help.
The second thing is not to use the jointable`s name as the name of the association.
The rest is just straight forward...
Making the association accessible in the Entity Class (Projekt.php):
protected $_accessible = [
'name' => true,
'projekteigenschaft' => true,
'nebenprojekte' => true,
];
ProjekteController.php ("add" and "edit"):
public function add()
{
$projekt = $this->Projekte->newEntity();
if ($this->request->is('post')) {
$projekt = $this->Projekte->patchEntity($projekt, $this->request->getData());
if ($this->Projekte->save($projekt)) {
$this->Flash->success(__('flash message'));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__('error message'));
}
$projekte = $this->Projekte->find('list');
$this->set(compact('projekt', 'projekte'));
}
public function edit($id = null)
{
$projekt = $this->Projekte->get($id, [
'contain' => ['Projekteigenschaften', 'Nebenprojekte']
]);
if ($this->request->is(['patch', 'post', 'put'])) {
$projekt = $this->Projekte->patchEntity($projekt, $this->request->getData());
if ($this->Projekte->save($projekt)) {
$this->Flash->success(__('flash message'));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__('error message'));
}
$projekte = $this->Projekte->find('list')->where(['id !=' => $id]);
$this->set(compact('projekt', 'projekte'));
}
In the templates like add.ctp or edit.ctp:
echo $this->Form->control('nebenprojekte._ids', ['options' => $projekte, 'multiple' => true]);
If you use another language than english, don´t forget to set the correct inflection rules.
bootstrap.php:
Inflector::rules('plural', [
'/^(projekt|nebenprojekt)$/i' => '\1e',
'/^(projekteigenschaft)$/i' => '\1en',
]);
Inflector::rules('singular', [
'/^(projekt|nebenprojekt)e$/i' => '\1',
'/^(projekteigenschaft)en$/i' => '\1',
]);

saving belongsToMany association with same keys but different _joinData

I have a belongsToMany relationship between two tables which is configured using a through table.
class UsersTable extends Table
{
public function initialize(array $config)
{
$this->belongsToMany('Groups', [
'through' => 'GroupsUsers',
]);
}
}
class GroupsTable extends Table
{
public function initialize(array $config)
{
$this->belongsToMany('Users', [
'through' => 'GroupsUsers',
]);
}
}
class GroupsUsersTable extends Table
{
public function initialize(array $config)
{
$this->belongsTo('Groups');
$this->belongsTo('Users');
}
}
I can make associations between users and groups, but not I can't figure out how to make multiple associates between the same user and groups, but with different _joinData.
This is how the join table is built:
$table = $this->table('groups_users');
$table->addColumn('user_id', 'integer');
$table->addColumn('group_id', 'integer');
$table->addColumn('role', 'string');
$table->create();
When I add or edit a group by adding users to it, the $data in beforeMarshal() is
object(ArrayObject) {
name => 'test group'
users => [
(int) 0 => [
'id' => (int) 1,
'_joinData' => [
'role' => 'writer'
]
],
(int) 1 => [
'id' => (int) 1,
'_joinData' => [
'role' => 'editor'
]
]
]
}
after patching the entity in the controller with
$entity = $this->Groups->patchEntity(
$entity,
$data,
['associated' => ['Users._joinData']]
);
I get the following $entity in beforeSave()
object(App\Model\Entity\Group) {
'id' => (int) 1,
'name' => 'test group',
'users' => [
(int) 0 => object(App\Model\Entity\User) {
'id' => (int) 1,
'username' => 'testuser',
'_joinData' => object(Cake\ORM\Entity) {
'role' => 'writer',
'[new]' => true,
'[accessible]' => [
'*' => true
],
'[dirty]' => [
'role' => true
],
'[original]' => [],
'[virtual]' => [],
'[hasErrors]' => false,
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'GroupsUsers'
},
'[new]' => false,
'[accessible]' => [
'username' => true,
'groups' => true,
'_joinData' => true
],
'[dirty]' => [
'_joinData' => true
],
'[original]' => [
'_joinData' => [
'role' => 'writer'
]
],
'[hasErrors]' => false,
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Users'
}
],
'[new]' => false,
'[accessible]' => [
'name' => true,
'users' => true
],
'[dirty]' => [
'users' => true,
'modified' => true
],
'[original]' => [
'modified' => object(Cake\I18n\FrozenTime) {
'time' => '2019-05-15T14:41:49+00:00',
'timezone' => 'UTC',
'fixedNowTime' => false
}
],
'[hasErrors]' => false,
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Groups'
}
So it looks like the Marshaller is removing the second "duplicate" user from the group, even though the _joinData is different. The default saveStrategy is replace, but manually changing it to append doesn't add the second association either.
How can I add the same user to the same group with different _joinData using the same join table.
The marshaller uses the primary key to identify records, and the collection of existing entities will then only hold one user entity instance, so even though the marshaller will add the different join data sets, it will set it on one and the same entity... long story short, the marshaller isn't (yet) capable of doing what you're trying to do. You may want to open an issue over at GitHub if there isn't one already.
For now you'll have to save the records separately, for example like this (untested, but you get the idea):
$group = $this->Groups->patchEntity($entity, $data, [
'fieldList' => ['name']
]);
$users = [];
foreach ($data['users'] as $userData) {
$user = $this->Groups->Users->newEntity();
$users[] = $this->Groups->Users->patchEntity($user, $userData);
}
$result = $this->Groups->getConnection()->transactional(function () use ($group, $users) {
if (!$this->Groups->save($group, ['atomic' => false])) {
return false;
}
if (!$this->Groups->Users->link($group, $users, ['atomic' => false])) {
return false;
}
return true;
});

How to save additional data to join Table if joined entities are created new

i am trying to save additional data to a belongsToMany join Table.
I followed the instructions here
But they are just in case the entities already exist, because an id is used it seems. But my entities should be new created and additional join data should be saved.
My save data looks like this. Everything is persisted fine, except the additional field 'type_keys'
(int) 0 => object(Cloud\Model\Entity\MediaObject) {
'media_object_type_id' => 'image',
'title' => '1482842705_1_749145',
'relative_path' => '/optional_images/1/1/',
'extension' => 'jpg',
'size' => (int) 142683,
'original_title' => 'logo.jpg',
'_joinData' => [
'type_key' => 'optional_image_1'
],
'[new]' => true,
'[accessible]' => [
'*' => true
],
'[dirty]' => [
'media_object_type_id' => true,
'title' => true,
'relative_path' => true,
'extension' => true,
'size' => true,
'original_title' => true,
'_joinData' => true
],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Cloud.MediaObjects'
}
Unfortunately just the joind ids in the join table are saved, but not the joinData field 'type_keys'
I would be happy if someone can give me a clue.
On further testing i found out that the join data gets overwritten when saving.
For your information: I am setting the media object join data in the beforeSave callback.
object(Cloud\Model\Entity\Touchpoint) {
'title' => 'test',
'user_id' => (int) 1,
'tp_image' => [
'name' => '',
'type' => '',
'tmp_name' => '',
'error' => (int) 4,
'size' => (int) 0
],
'optional_image_1' => [
'name' => 'logo.jpg',
'type' => 'image/jpeg',
'tmp_name' => '/tmp/phpMeTwuQ',
'error' => (int) 0,
'size' => (int) 142683
],
'created' => object(Cake\I18n\Time) {
'time' => '2016-12-27T13:19:03+00:00',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\Time) {
'time' => '2016-12-27T13:19:03+00:00',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'brand_id' => (int) 1,
'media_objects' => [
(int) 0 => object(Cloud\Model\Entity\MediaObject) {
'media_object_type_id' => 'image',
'title' => '1482844743_1_988232',
'relative_path' => '/optional_images/1/1/',
'extension' => 'jpg',
'size' => (int) 142683,
'original_title' => 'logo.jpg',
'_joinData' => object(Cake\ORM\Entity) {
'touchpoint_id' => (int) 8,
'media_object_id' => (int) 8,
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'MediaObjectsTouchpoints'
},
'created' => object(Cake\I18n\Time) {
'time' => '2016-12-27T13:19:03+00:00',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\Time) {
'time' => '2016-12-27T13:19:03+00:00',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'id' => (int) 8,
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [],
'[original]' => [
'_joinData' => [
'type_key' => 'optional_image_1'
]
],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Cloud.MediaObjects'
}
],
'id' => (int) 8,
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Cloud.Touchpoints'
}
So i know it gets overwritten, but i am not sure how to do this the right way?
Ok i found the solution now.
Since i saw an entity is created as _joinData i created an entity myself and did set the property in the entity myself, this way the _joinData does not get replaced, but just enriched with the ids.
$joinTable = TableRegistry::get('MediaObjectsTouchpoints');
$newMediaObject->_joinData = $joinTable->newEntity();
$newMediaObject->_joinData->type_key = 'something';
$entity->media_objects[] = $newMediaObject;

Using SQL Functions in cakephp3.2 ORM query builder is not working

I am trying to run a query through the query builder . So the query is running but I get incorrect result.
The main problem is when I use the min() function I don't get correct result and even I tried to run the firstDue query alone but still there is no result. How ever when I remove the min() function I get all payment instalments.
(int) 2 => object(App\Model\Entity\Order) {
'order_id' => '10000',
'final_price' => (int) 775,
'payment_status_id' => (int) 2,
'status2' => (int) 1,
'client_deadline_orig' => object(Cake\I18n\FrozenTime) {
'time' => '2016-09-05T14:08:40+01:00',
'timezone' => 'Europe/London',
'fixedNowTime' => false
},
'payment_instalments' => [], // The payment instalments is empty
'customer_files' => [],
'order_master' => object(Cake\ORM\Entity) {
'order_id' => '10000',
'subj1' => 'Mathematical & Theoretical Physics',
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'OrderMasters'
},
'subj1' => 'Mathematical & Theoretical Physics',
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [
'subj1' => true
],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Orders'
},
My Tables Associations
Orders Table
class OrdersTable extends Table
{
public function initialize(array $config)
{
$this->table('orders');
$this->primaryKey('order_id');
// Relationships
$this->addAssociations([
'belongsTo' => [
'Users' => [
'foreignKey' => 'customer_id'
]
],
'hasMany' => [
'PaymentInstalments' => [
'foreignKey' => 'order_id'
]
]
]);
}
Transactions Table
class TransactionsTable extends Table
{
public function initialize(array $config)
{
// Relationships
$this->addAssociations([
'belongsTo' => [
'Orders'
],
'hasOne' => [
'PaymentInstalments'
]
]);
}
PaymentInstalments Table
class PaymentInstalments extends Table
{
public function initialize(array $config)
{
// Relationships
$this->belongsTo('Orders');
$this->belongsTo('Transactions');
}
public function findFirstDue(Query $query, array $options)
{
$alias = $this->alias();
$query
->select([
'id' => "MIN($alias.id)",
'order_id', 'amount', 'date_due', 'transaction_id'
])
// ->where(function ($exp, $q) use ($alias) {
// return $exp->isNull('transaction_id');
// });
->where(["$alias.transaction_id IS NULL"]);
return $query;
}
===============================================================
I want to get all the instalments that their transaction_id IS NULL.
Here is my main query in my controller:
$this->loadModel('Orders');
$orders = $this->Orders
->select([
'order_id', 'final_price', 'payment_status_id', 'status2',
'client_deadline_orig'
])
->contain([
'PaymentInstalments' => function($q) {
return $q->find('firstDue');
}
])
->where(['Orders.status2 !=' => 7])
->all();
I thought the problem might be because of isNull() function but it is not that's why I try to write the condition manually.
Note: This query was working on cakephp-3.1 and since we have updated our application to the latest version of cakephp-3.2 this problem happened.
Any help please.

How to print _matchingData object value in cakephp 3

I have printed object and trying to print Tenats.stage
<?php foreach ($tenancies as $tenancy): ?>
<td><?= debug($tenancy); ?></td>
Print this =>
object(App\Model\Entity\Tenancy) {
'created' => object(Cake\I18n\FrozenTime) {
'time' => '2016-03-18T15:57:40+00:00',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'tenants' => [],
'property' => object(Cake\ORM\Entity) {
'id' => (int) 4110,
'address1' => '119 Alan Moss Road',
'postcode' => 'le115ly',
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Properties'
},
'_matchingData' => [
'Tenants' => object(Cake\ORM\Entity) {
'stage' => (int) 2,
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Tenants'
}
],
I need to 'stage' value
Any help please
That's how to print _matchingData
<td><?= h($tenancy->_matchingData['Tenants']->stage); ?></td>
But if you specify the main parents field id (Tenancy.id) automaticaly your data will look much much better. for example my parent model is "Tenancy" Now I am getting Tenant.id and Tenancy.id and Property.id :
$tenancies = $this
->find()
->select([
'Tenancy.id', 'Tenancy.created', 'Tenancy.stage',
'Properties.id', 'Properties.address1', 'Properties.postcode',
'Tenants.stage',
])
->contain('Properties', function(\Cake\ORM\Query $query) {
return $query->where([
'Properties.active' => 1
]);
})
->contain([
'Tenants'
])
->matching('Tenants', function(\Cake\ORM\Query $query) {
return $query->where([
'Tenants.active' => 1
]);
})
->where([
'Tenancy.active' => 1,
$conditions
])
->order([
'Tenancy.created' => 'DESC',
'Tenants.tenancy_id'
]);
return $tenancies;
}
It prints the array with deep associations which is cool and I can get my tenants property like this:
<td><?= h($tenancy->tenants->stage); ?></td>
Prints=>
0 => object(App\Model\Entity\Tenancy) {
'id' => (int) 3923,
'created' => object(Cake\I18n\FrozenTime) {
'time' => '2016-03-19T13:12:32+00:00',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'stage' => (int) 2,
'tenants' => [
(int) 0 => object(Cake\ORM\Entity) {
'id' => (int) 8903,
'user_id' => (int) 15318,
'tenancy_id' => (int) 3923,
'needs_guarantor' => true,
'guarantor_id' => null,
'holding_fee' => (float) 50,
Result: Make sure always you write your query properly so you access your data nice and tidy.

Resources