CakePHP filter a deep associated find - cakephp

I have a deep associated find and one association is retrieving too many none related records for modules_employees.
I should see only one record for modules_employees under the course_modules but it retrieves many because they can be many with course_modules_id but only one with courses_employee_id.
The modules_employees table
'id' => (int) 18,
'courses_employee_id' => (int) 31,
'course_module_id' => (int) 7,
'completed_on' => null,
CoursesEmployee->course->course_modules->modules_employees
CoursesEmployeesController.php
public function player($id = null)
{
$coursesEmployee = $this->CoursesEmployees->get($id, [
'contain' =>
[
'Employees',
'Courses',
'CourseModules',
'Courses.CourseModules',
'Courses.CourseModules.ModulesEmployees',
'Courses.CourseFiles'
]
]);
$this->set('coursesEmployee', $coursesEmployee);
debug($coursesEmployee);
$this->set('_serialize', ['coursesEmployee']);
}
The current find object, you will see one of the course_modules has two modules_employees when I should have one.
object(App\Model\Entity\CoursesEmployee) {
'id' => (int) 31,
'employee_id' => (int) 3,
'course_id' => (int) 3,
'course_module_id' => (int) 7,
'course_module' => object(App\Model\Entity\CourseModule) {
'id' => (int) 7,
'course_id' => (int) 3,
'name' => 'Module 2',
},
'course' => object(App\Model\Entity\Course) {
'id' => (int) 3,
'name' => 'Treacys Hotel Induction Training',
'course_files' => [
(int) 0 => object(App\Model\Entity\CourseFile) {
'id' => (int) 2,
'name' => 'Manual_Handling_doc.txt',
'type' => 'doc',
}
],
'course_modules' => [
(int) 0 => object(App\Model\Entity\CourseModule) {
'id' => (int) 6,
'course_id' => (int) 3,
'name' => 'Module 1',
'module_order' => (int) 1,
'modules_employees' => [
(int) 0 => object(App\Model\Entity\ModulesEmployee) {
'id' => (int) 1,
'courses_employee_id' => (int) 0,
'course_module_id' => (int) 6,
'started_on' => object(Cake\I18n\Time) {
'time' => '2015-09-08T04:16:16+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'completed_on' => object(Cake\I18n\Time) {
'time' => '2015-09-09T08:22:16+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'completed' => true,
'deleted' => null,
'[new]' => false,
'[accessible]' => [
'employee_id' => true,
'module_id' => true,
'started_on' => true,
'completed_on' => true,
'completed' => true,
'employee' => true,
'module' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[repository]' => 'ModulesEmployees'
}
],
'[repository]' => 'CourseModules'
},
(int) 1 => object(App\Model\Entity\CourseModule) {
'id' => (int) 7,
'course_id' => (int) 3,
'name' => 'Module 2',
'module_order' => (int) 2,
'modules_employees' => [
(int) 0 => object(App\Model\Entity\ModulesEmployee) {
'id' => (int) 2,
'courses_employee_id' => (int) 31,
'course_module_id' => (int) 7,
'started_on' => object(Cake\I18n\Time) {
'time' => '2015-09-17T00:00:00+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'completed_on' => null,
'[repository]' => 'ModulesEmployees'
},
(int) 1 => object(App\Model\Entity\ModulesEmployee) {
'id' => (int) 18,
'courses_employee_id' => (int) 32,
'course_module_id' => (int) 7,
'started_on' => object(Cake\I18n\Time) {
'time' => '2015-09-17T00:00:00+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'completed_on' => null,
'[repository]' => 'ModulesEmployees'
}
],
'[repository]' => 'CourseModules'
},
],
},
'employee' => object(App\Model\Entity\Employee) {
'id' => (int) 3,
'user_id' => (int) 4,
},
'[repository]' => 'CoursesEmployees'
}

You should look into matching
http://book.cakephp.org/3.0/en/orm/query-builder.html#filtering-by-associated-data
$query = $this->CoursesEmployees->findById($id)
->contain(['Your_Models_You_Wanna_Contain'])
->matching('Courses.CourseModules.ModulesEmployees', function ($q) use ($id) {
return $q->where(['courses_employee_id' => $id]);
});
if nothing matches then you wont get a CourseEmployee back aswell, if you would still need that you could also use contain:
http://book.cakephp.org/3.0/en/orm/retrieving-data-and-resultsets.html#passing-conditions-to-contain
$query = $this->CoursesEmployees->findById($id)->contain([
'Courses.CourseModules.ModulesEmployees' => function ($q) use ($id) {
return $q
->where(['courses_employee_id' => $id]);
}
]);

Related

CakePHP 4 multiple checkboxes

I want to populate a checkbox group with the array JournalEntry[strategy][strategies_conditions]
I then want to have the checkboxes selected that are contained in JournalEntry[journal_entries_strategy_conditions]
I have the checkboxes displaying but not linked correctly to the correct fields of name and id
This is the code I have in the edit.php
<?php
echo $this->Form->control('journal_id', ['options' => $journals]);
echo $this->Form->control('ticket_number');
echo $this->Form->control('strategy_id', ['options' => $strategies, 'empty' => true, 'onChange' => 'getComboA(this)']);
debug($journalEntry);
?>
<div id="stategy-condition">
<?php echo $this->Form->control('journal_entries_strategy_conditions.strategies_condition_id',
[
'type' => 'select',
'multiple' => 'checkbox',
'options' => $journalEntry[strategy][strategies_conditions],
'selected' => $journalEntry[journal_entries_strategy_conditions]
]); ?>
</div>
With this I get this output, as you can see it is using the object for the <label> and <input value="1" is set to the id value
<div class="input select">
<label for="strategy-id">Strategy</label>
<input type="hidden" name="strategy_id" value="">
<div class="checkbox">
<label for="strategy-id-0">
<input type="checkbox" name="strategy_id[]" value="0" id="strategy-id-0">{
"id": 1,
"strategy_id": 5,
"name": "zxcasd",
"level": "0",
"created": "2020-08-01T21:21:11+00:00",
"modified": "2020-08-01T21:21:11+00:00"
}</label>
</div>
<div class="checkbox">
<label for="strategy-id-1">
<input type="checkbox" name="strategy_id[]" value="1" id="strategy-id-1">{
"id": 2,
"strategy_id": 5,
"name": "zxcasd",
"level": "0",
"created": "2020-08-01T21:21:11+00:00",
"modified": "2020-08-01T21:21:11+00:00"
}</label>
</div>
<div class="checkbox">
<label for="strategy-id-2">
<input type="checkbox" name="strategy_id[]" value="2" id="strategy-id-2">{
"id": 3,
"strategy_id": 5,
"name": "zxcad",
"level": "0",
"created": "2020-08-01T21:21:11+00:00",
"modified": "2020-08-01T21:21:11+00:00"
}</label></div></div>
Here is the data:
object(App\Model\Entity\JournalEntry) {
'id' => (int) 20,
'journal_id' => (int) 1,
'ticket_number' => 'sdfsdfsdf',
'strategy_id' => (int) 5,
'timeframe' => '',
'created' => object(Cake\I18n\FrozenTime) {
'time' => '2020-08-25 20:51:42.000000+00:00',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\FrozenTime) {
'time' => '2020-08-25 20:51:42.000000+00:00',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'journal_entries_strategy_conditions' => [
(int) 0 => object(App\Model\Entity\JournalEntriesStrategyCondition) {
'id' => (int) 8,
'journal_entry_id' => (int) 20,
'strategies_condition_id' => (int) 1,
'created' => object(Cake\I18n\FrozenTime) {
'time' => '2020-08-25 20:51:42.000000+00:00',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\FrozenTime) {
'time' => '2020-08-25 20:51:42.000000+00:00',
'timezone' => 'UTC',
'fixedNowTime' => false
},
}
],
'strategy' => object(App\Model\Entity\Strategy) {
'id' => (int) 5,
'user_id' => (int) 1,
'name' => 'zxcasd',
'description' => 'zxcasd',
'one_hundred_trades' => (int) 0,
'created' => object(Cake\I18n\FrozenTime) {
'time' => '2020-08-01 21:21:11.000000+00:00',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\FrozenTime) {
'time' => '2020-08-01 21:21:11.000000+00:00',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'strategies_conditions' => [
(int) 0 => object(App\Model\Entity\StrategiesCondition) {
'id' => (int) 1,
'strategy_id' => (int) 5,
'name' => 'zxcasd',
'level' => '0',
'created' => object(Cake\I18n\FrozenTime) {
'time' => '2020-08-01 21:21:11.000000+00:00',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\FrozenTime) {
'time' => '2020-08-01 21:21:11.000000+00:00',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'[new]' => false,
'[accessible]' => [
'strategy_id' => true,
'name' => true,
'level' => true,
'created' => true,
'modified' => true,
'strategy' => true
]
},
(int) 1 => object(App\Model\Entity\StrategiesCondition) {
'id' => (int) 2,
'strategy_id' => (int) 5,
'name' => 'zxcasd',
'level' => '0',
'created' => object(Cake\I18n\FrozenTime) {
'time' => '2020-08-01 21:21:11.000000+00:00',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\FrozenTime) {
'time' => '2020-08-01 21:21:11.000000+00:00',
'timezone' => 'UTC',
'fixedNowTime' => false
}
},
(int) 2 => object(App\Model\Entity\StrategiesCondition) {
'id' => (int) 3,
'strategy_id' => (int) 5,
'name' => 'zxcad',
'level' => '0',
'created' => object(Cake\I18n\FrozenTime) {
'time' => '2020-08-01 21:21:11.000000+00:00',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\FrozenTime) {
'time' => '2020-08-01 21:21:11.000000+00:00',
'timezone' => 'UTC',
'fixedNowTime' => false
},
}
],
},
'[new]' => false,
This the request date for edit.php
[
'journal_id' => '1',
'ticket_number' => 'test con',
'pair' => '',
'buy_sell' => '',
'personal_notes' => '',
'entry_date_time' => '',
'entry_price' => '',
'strategy_id' => '5',
'journal_entries_strategy_conditions' => [
'strategies_condition_id' => [
(int) 0 => '1'
]
],
'timeframe' => '',
'position_size' => '',
'sl' => '',
'tp' => '',
'market_conditions' => '',
'entry_toughts' => '',
'close_date_time' => '',
'close_price' => '',
'profit' => '',
'fees' => '',
'high_price' => '',
'low_price' => '',
'exit_thoughts' => '',
'feeling_before' => '',
'feeling_after' => ''
]
add.php
[
'journal_id' => '1',
'ticket_number' => 'sdfdsf',
'pair' => '',
'buy_sell' => '',
'personal_notes' => '',
'entry_date_time' => '',
'entry_price' => '',
'strategy_id' => '5',
'journal_entries_strategy_conditions' => [
(int) 0 => [
'strategies_condition_id' => '1'
],
(int) 1 => [
'strategies_condition_id' => '2'
]
],
'timeframe' => '',
'position_size' => '',
'sl' => '',
'tp' => '',
'market_conditions' => '',
'entry_toughts' => '',
'close_date_time' => '',
'close_price' => '',
'profit' => '',
'fees' => '',
'high_price' => '',
'low_price' => '',
'exit_thoughts' => '',
'feeling_before' => '',
'feeling_after' => ''
]
There is no selected option, the option to provide values for selection is named val or value, and like the options option, it expects a flat key => value array (there's an exception if you want to provide attributes for <option> elements, in that case you can use nested arrays with text and value keys).
For options the array key will be use for the <option> element's value attribute, and the array value will be used for the content of the element.
For value the array value will be used for matching against the options array's keys, ie AFAICT you'd need an array of strategies_condition_id.
Often times values for select controls are being prepared using the list finder, you'll see that in baked controllers. However since you have nested associations, that's not necessarily feasible, and you're possibly better of converting the data after the fact, which can easily be done using collections.
For example in your view template:
<div id="stategy-condition">
<?php echo $this->Form->control('journal_entries_strategy_conditions', [
'type' => 'select',
'multiple' => 'checkbox',
'options' =>
collection($journalEntry['strategy']['strategies_conditions'])
->combine('id', 'name')
->toArray(),
'value' =>
collection($journalEntry['journal_entries_strategy_conditions'])
->extract('strategies_condition_id')
->toArray()
]); ?>
</div>
The combine() call should build a collection like:
[
1 => 'zxcasd',
2 => 'zxcasd',
3 => 'zxcad',
]
and the extract() should result in a collection containing this:
[
0 => 1
]
which should result in the first checkbox being checked.
Cookbook > Collections > combine()
Cookbook > Collections > extract()
As far as your control name problem goes, there are many ways to solve this, you could for example use a custom template where you hardcode the input name:
echo $this->Form->control('journal_entries_strategy_conditions', [
'type' => 'select',
// ...
'templates' => [
'checkbox' =>
'<input
type="checkbox"
name="journal_entries_strategy_conditions[][strategies_condition_id]"
value="{{value}}"
{{attrs}}>',
]
]);
Cookbook > Views > Helpers > Form > Options for Control
Cookbook > Views > Helpers > Form > Customizing the Templates FormHelper Uses
Or transform the data before marshalling (patching), using the beforeMarshal callback in your JournalEntriesTable class:
public function beforeMarshal(
\Cake\Event\EventInterface $event,
\ArrayObject $data,
\ArrayObject $options
) {
if (isset($data['journal_entries_strategy_conditions']['strategies_condition_id']) {
$ids = $data['journal_entries_strategy_conditions']['strategies_condition_id'];
$conditions = [];
foreach ($ids as $id) {
$conditions[] = [
'strategies_condition_id' => $id,
];
}
$data['journal_entries_strategy_conditions'] = $conditions;
}
}
This would transform the data from:
'journal_entries_strategy_conditions' => [
'strategies_condition_id' => [
'1',
'2'
],
],
to:
'journal_entries_strategy_conditions' => [
[
'strategies_condition_id' => '1'
],
[
'strategies_condition_id' => '2'
]
],
Cookbook > Database Access & ORM > Saving Data > Modifying Request Data Before Building Entities
Or even create the individual checkboxes manually, where you have proper control over every aspect of every form control, including the name:
echo $this->Form->label('journal_entries_strategy_conditions');
echo $this->Form->hidden('journal_entries_strategy_conditions', ['value' => '']);
$selectedIds = collection($journalEntry['journal_entries_strategy_conditions'])
->extract('strategies_condition_id')
->toArray();
foreach ($journalEntry['strategy']['strategies_conditions'] as $index => $condition) {
echo $this->Form->control(
"journal_entries_strategy_conditions.{$index}.strategies_condition_id",
[
'type' => 'checkbox',
'hiddenField' => false,
'label' => $condition['name'],
'value' => $condition['id'],
'checked' => in_array($condition['id'], $selectedIds, true),
]
);
}
This would create name attributes like:
journal_entries_strategy_conditions[0][strategies_condition_id]
journal_entries_strategy_conditions[1][strategies_condition_id]
...
Cookbook > Views > Helpers > Form > Creating Select, Checkbox and Radio Controls

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;

cant save associated new records in cakephp3

To save new records in associated data with a many to 1 and a many to many as below what do I do ? I cant get it to save my data .
I get an error on trying to save a to the guardian without an id but it is a new record and I couldn't this working
controller
if ($this->request->is(['patch', 'post', 'put'])) {
$mydata=$this->request->data;
$guardian =$this->Guardians->newEntity();
$guardian->guardian_first_name = $mydata['Guardians']['guardian_first_name'];
$guardian->guardian_last_name = $mydata['Guardians']['guardian_last_name'];
$guardian->guardian_mobile = $mydata['Guardians']['guardian_mobile'];
$guardian->guardian_email = $mydata['Guardians']['guardian_email'];
$student = $this->Students->newEntity( $mydata,['associated' => ['AvailabilityForStudents','Subjects','Guardians']] );
$student->guardians = [ $guardian];
$val= $this->Students->save($student,[
'validate' => false ]);
public function initialize(array $config)
{
parent::initialize($config);
$this->table('students');
$this->displayField('id');
$this->primaryKey('id');
$this->addBehavior('Timestamp');
$this->belongsTo('Users', [
'foreignKey' => 'user_id',
'joinType' => 'LEFT'
]);
$this->belongsTo('Guardians', [
'foreignKey' => 'guardian_id',
'joinType' => 'LEFT'
]);
$this->hasMany('AvailabilityForStudents', [
'foreignKey' => 'student_id'
]);
$this->belongsToMany('Subjects', [
'foreignKey' => 'student_id',
'targetForeignKey' => 'subject_id',
'joinTable' => 'students_subjects'
]);
}
http://book.cakephp.org/3.0/en/orm/saving-data.html#saving-with-associations
update-returned data
[
'first_name' => 'a1',
'last_name' => 'a2',
'student_mobile' => '',
'school' => '9',
'class_year' => '9',
'tutor_gender_preference' => 'No Preference',
'doing_assessment' => '0',
'tutoring_typest_id' => '1',
'address_street' => '1 gghh',
'address_suburb' => 'seagg',
'address_postcode' => '3111',
'address_state' => 'Vic',
'address_lat' => '',
'address_long' => '',
'school_address_street' => '',
'school_address_suburb' => '',
'school_address_postcode' => '',
'school_address_lat' => '',
'school_address_long' => '',
'Guardians' => [
'guardian_first_name' => 'aa',
'guardian_last_name' => 'aa',
'guardian_phone' => '03534535',
'guardian_mobile' => '0000000000',
'guardian_email' => 'a#ww.com'
],
'subjects' => [
'_ids' => [
(int) 0 => '1'
]
],
'AvailabilityForStudents' => [
'Monday' => [
'weekday' => 'Monday',
'not_available' => '0',
'start_time' => '9:00',
'end_time' => '10:00'
],
'Tuesday' => [
'weekday' => 'Tuesday',
'not_available' => '0',
'start_time' => '9:00',
'end_time' => '10:00'
],
'Wednesday' => [
'weekday' => 'Wednesday',
'not_available' => '0',
'start_time' => '9:00',
'end_time' => '10:00'
],
'Thursday' => [
'weekday' => 'Thursday',
'not_available' => '0',
'start_time' => '9:00',
'end_time' => '10:00'
],
'Friday' => [
'weekday' => 'Friday',
'not_available' => '0',
'start_time' => '9:00',
'end_time' => '10:00'
],
'Saturday' => [
'weekday' => 'Saturday',
'not_available' => '0',
'start_time' => '9:00',
'end_time' => '10:00'
],
'Sunday' => [
'weekday' => 'Sunday',
'not_available' => '0',
'start_time' => '9:00',
'end_time' => '10:00'
]
]
]
patched data
object(App\Model\Entity\Student) {
'first_name' => 'a1',
'last_name' => 'a2',
'student_mobile' => '',
'school' => '9',
'class_year' => (int) 9,
'tutor_gender_preference' => 'No Preference',
'doing_assessment' => (int) 0,
'tutoring_typest_id' => (int) 1,
'address_street' => '1 gghh',
'address_suburb' => 'seagg',
'address_postcode' => '3111',
'address_state' => 'Vic',
'address_lat' => '',
'address_long' => '',
'school_address_street' => '',
'school_address_suburb' => '',
'school_address_postcode' => '',
'school_address_lat' => '',
'school_address_long' => '',
'Guardians' => [
'guardian_first_name' => 'aa',
'guardian_last_name' => 'aa',
'guardian_phone' => '03534535',
'guardian_mobile' => '0000000000',
'guardian_email' => 'a#ww.com'
],
'subjects' => [
(int) 0 => object(App\Model\Entity\Subject) {
'id' => (int) 1,
'name' => 'English: Prep- Grade 3',
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Subjects'
}
],
'AvailabilityForStudents' => [
'Monday' => [
'weekday' => 'Monday',
'not_available' => '0',
'start_time' => '9:00',
'end_time' => '10:00'
],
'Tuesday' => [
'weekday' => 'Tuesday',
'not_available' => '0',
'start_time' => '9:00',
'end_time' => '10:00'
],
'Wednesday' => [
'weekday' => 'Wednesday',
'not_available' => '0',
'start_time' => '9:00',
'end_time' => '10:00'
],
'Thursday' => [
'weekday' => 'Thursday',
'not_available' => '0',
'start_time' => '9:00',
'end_time' => '10:00'
],
'Friday' => [
'weekday' => 'Friday',
'not_available' => '0',
'start_time' => '9:00',
'end_time' => '10:00'
],
'Saturday' => [
'weekday' => 'Saturday',
'not_available' => '0',
'start_time' => '9:00',
'end_time' => '10:00'
],
'Sunday' => [
'weekday' => 'Sunday',
'not_available' => '0',
'start_time' => '9:00',
'end_time' => '10:00'
]
],
'student_enq' => false,
'user_id' => (int) 7,
'student_inactive' => false,
'acknowledge' => (int) 0,
'is_email_notify' => (int) 0,
'days_joined' => (int) 0,
'satisfaction_rating' => (int) 0,
'student_unallocated' => false,
'admin_satisfaction_rating' => (int) 0,
'another_assessment' => (int) 0,
'numeracy_active' => (int) 0,
'is_waiting_assessment' => (int) 0,
'group_status' => (int) 0,
'address_billing' => '4',
'[new]' => true,
'[accessible]' => [
'*' => true
],
'[dirty]' => [
'first_name' => true,
'last_name' => true,
'student_mobile' => true,
'school' => true,
'class_year' => true,
'tutor_gender_preference' => true,
'doing_assessment' => true,
'tutoring_typest_id' => true,
'address_street' => true,
'address_suburb' => true,
'address_postcode' => true,
'address_state' => true,
'address_lat' => true,
'address_long' => true,
'school_address_street' => true,
'school_address_suburb' => true,
'school_address_postcode' => true,
'school_address_lat' => true,
'school_address_long' => true,
'Guardians' => true,
'subjects' => true,
'AvailabilityForStudents' => true,
'student_enq' => true,
'user_id' => true,
'student_inactive' => true,
'acknowledge' => true,
'is_email_notify' => true,
'days_joined' => true,
'satisfaction_rating' => true,
'student_unallocated' => true,
'admin_satisfaction_rating' => true,
'another_assessment' => true,
'numeracy_active' => true,
'is_waiting_assessment' => true,
'group_status' => true,
'address_billing' => true
],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Students'
}
I was also facing the similar problem and after all R&D, I tried this code and it worked. Hope you'll also get benefited. Here the code goes:
Let's say you have a controller "UsersController" associated with "RolesController" with "id". Then add the below line of code in your action under UsersController:
$this->loadModel('Roles');
$roles = $this->Roles->find('list');
$roles = $roles->toArray();
$this->set(compact('roles'));
Now make the following changes in your action's view file in Template folder:
echo $this->Form->select('role_id', $roles);
Here, we have assigned that variable to our form field.
With these changes, you should be able to do your task. If still face any issue, feel free to ask in comments.
KEEP CODING! HAVE FUN! :)
I suggest splitting the entity creation.
First, create a new entity with $student = $this->Students->newEntity();
And then patch you data to the entity like :
$student = $this->Student->patchEntity($mydata,['associated' => ['AvailabilityForStudents','Subjects','Guardians']]);
Maybe the patchEntity() method understand the association in a better manner.
Hope this solves your problem!

How to get only selected fields from rightJoin() and contain() in cakephp3

cakephp 3.2.3x
I am trying to show custom fields from right join which is contained (left joined) with an other table and it is not working. How ever contain custom fields is working.
Note 1: When I get rid of contain() my ORM works as I am expecting.
$properties = $this->find()
->select([
'Property.id', 'Property.company_id', 'Property.address1', 'Property.postcode',
'Tenancies.property_id', 'Tenancies.start_date', 'Tenancies.end_date', 'Tenancies.deposit_total',
])
->rightJoin(['Tenancies' => 'tenancy'],[
'Tenancies.property_id = Property.id',
'Tenancies.active = 1'
])
->contain([
'Tenancies.Tenants' => function($q) {
return $q
->select([
'Tenants.id', 'Tenants.stage', 'Tenants.tenancy_id', 'Tenants.holding_fee',
])
->where([
'active = 1',
]);
}
])
->where(['Property.active = 1', $conditions]);
Note 2: Generated sql is correct but it is not applying to the query.
'SELECT Property.id AS Property__id, Property.company_id AS
Property__company_id, Property.address1 AS Property__address1,
Property.postcode AS Property__postcode,
Tenancies.property_id AS Tenancies__property_id,
Tenancies.start_date AS Tenancies__start_date,
Tenancies.end_date AS Tenancies__end_date,
Tenancies.deposit_total AS Tenancies__deposit_total FROM
property Property RIGHT JOIN tenancy Tenancies ON
(Tenancies.property_id = Property.id AND Tenancies.active = 1) WHERE
(Property.active = 1 AND Property.company_id = :c0)'
The query should show me only 3 fields of 'Tenancies' but it retrieves all the Tenancies fields.
(int) 0 => [
'id' => (int) 102,
'company_id' => (int) 3,
'address1' => 'Grace Dieu Court',
'postcode' => 'LE11 4QH',
'tenancies' => [
(int) 0 => [
'id' => (int) 16,
'property_id' => (int) 102,
'landlord_id' => (int) 65,
'agent_id' => (int) 7,
'company_id' => (int) 3,
'bedroom' => (int) -1,
'created' => object(Cake\I18n\FrozenTime) {
'time' => '2015-05-08T09:30:41+00:00',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'active' => true,
...
... ## } The rest of all fileds
'tenants' => [
(int) 0 => [
'id' => (int) 16,
'stage' => (int) 7,
'tenancy_id' => (int) 16,
'holding_fee' => (float) 50
],
(int) 1 => [
'id' => (int) 17,
'stage' => (int) 7,
'tenancy_id' => (int) 16,
'holding_fee' => (float) 50
]
]
]
]
],

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