HasOne associations table is not saving - cakephp

Hi I'm trying to save data across 2 tables (Entries and Conditions) at the same time. Entries has a column called foreign_key which is a relation to the Conditions primary id.
I was testing the saving portion and one of my tables (Conditions) saved but my other table (Entries) did not.
Entry.php
protected $_accessible = [
'metadata' => true,
'type' => true,
'foreign_key' => true,
'created' => true,
'modified' => true,
'condition' => true
];
Condition.php
protected $_accessible = [
'user_id' => true,
'data' => true,
'created' => true,
'modified' => true,
'user' => true,
'entry' => true
];
ConditionsTable.php (where I declared the association)
public function initialize(array $config)
{
parent::initialize($config);
$this->setTable('conditions');
$this->setDisplayField('id');
$this->setPrimaryKey('id');
$this->addBehavior('Timestamp');
$this->belongsTo('Users', [
'foreignKey' => 'user_id',
'joinType' => 'INNER'
]);
$this->hasOne('Entries', [
'foreignKey' => 'foreign_key',
'bindingKey' => 'id',
'propertyName' => 'entries',
'joinType' => 'INNER'
]);
}
DataControlellr.php (where I'm testing the saving)
$this->loadModel('Conditions');
$data = [
'user_id' => 'b26ee991-a27c-441b-a78b-dd2a1dbf5164',
'data' => json_encode(['test'=>1,'test2' => 2]),
'entry' =>[
'meta' => json_encode(['test'=>1,'test2' => 2]),
'type' => 'conditions'
]
];
$entity = $this->Conditions->newEntity($data,['associated' => 'Entries']);
//dd($entity);
dd($this->Conditions->save($entity));
exit;
}
So again entries table is not saving a row and conditions is, I believe I'm using the right association (has one) but maybe that not the right logic? Much help is appreciated.

The key in your data and your association name need to match. You probably want to change your association to this:
$this->hasOne('Entries', [
'foreignKey' => 'foreign_key',
'bindingKey' => 'id',
'joinType' => 'INNER'
]);
assuming that the class for the fhir_entries table is called EntriesTable, not FhirEntriesTable.
Alternately, leave the association named as it is but change the propertyName to entry (hasOne properties should be singular). Or, change it to fhir_entry and the key in the data array from entry to fhir_entry to match.

Related

Belongs to Many: save custom field

I need help with saving/updating belongsToMany data with custom field.
I have a tables acl, managers, groups, sections.
I need to save/update data in acl table from sections/edit or sections/add
acl table
id|target_id|target_type|section_id
I need set target_id data 'user' or 'group' depending entities.
edit.ctp
echo $this->Form->control('managers._ids', ['class' => 'multiple', 'multiple' => true]);
echo $this->Form->control('groups._ids', ['class' => 'multiple', 'multiple' => true]);
SectionsTable.php
$this->belongsToMany('Managers', [
'joinTable' => 'acl',
'through' => 'Acl',
'foreignKey' => 'section_id',
'targetForeignKey' => 'target_id',
'conditions' => [
'target_type' => 'user'
]
]);
$this->belongsToMany('Groups', [
'joinTable' => 'acl',
'through' => 'Acl',
'foreignKey' => 'section_id',
'targetForeignKey' => 'target_id',
'conditions' => [
'target_type' => 'group'
]
]);
AclTable.php
$this->belongsTo('Managers', [
'foreignKey' => 'target_id',
'conditions' => [
'target_type' => 'user'
]
]);
$this->belongsTo('Groups', [
'foreignKey' => 'target_id',
'conditions' => [
'target_type' => 'group'
]
]);
I tried to use _joinData, but nothing work
before and after patchEntity()
foreach ($section->groups as &$group) {
$group->_joinData = ['target_type' => 'group'];
}
whithout save()
foreach ($this->request->data['managers']['_ids'] as $id) {
$manager = $this->Sections->Managers->get($id);
$manager->_joinData = new Entity(['target_type' => 'user'], ['markNew' => true]);
$this->Sections->Managers->link($section, [$manager]);
}
$this->request->data has a follow structure:
[
'controller' => '*',
'action' => '*',
'title' => '*',
'managers' => [
'_ids' => [
'0' => '*',
'1' => '*',
'2' => '*',
]
],
'groups' => [
'_ids' => [
'0' => '*',
'1' => '*',
'2' => '*',
]
]
]
Alltimes error: Cannot insert row, some of the primary key values are missing. Got (3, 114, ), expecting (target_id, section_id, target_type)
Now working with following code
$section = $this->Sections->patchEntity($section, $this->request->data, ['associated' => ['Managers', 'Groups']]);
foreach ($section->managers as &$manager) {
$manager->_joinData = new Entity([
'target_id' => $manager->id,
'target_type' => 'user',
'section_id' => $section->id
], ['markNew' => true]);
}
foreach ($section->groups as &$group) {
$group->_joinData = new Entity([
'target_id' => $group->id,
'target_type' => 'group',
'section_id' => $section->id
], ['markNew' => true]);
}
if ($this->Sections->save($section, ['associated' => ['Managers', 'Groups']])) {
$this->Flash->success(__('The section has been saved.'));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__('The section could not be saved. Please, try again.'));
But, maybe can do it don't listing all fields?
Also I need to create/add new records to acl table when adding new section
But section_id unavailable until save(). Can I save/add acl records by associations
Updated
AclTAble.php
$this->setPrimaryKey(['target_type', 'target_id', 'section_id']);
.
.
.
$this->belongsTo('Managers', [
'foreignKey' => 'target_id',
'conditions' => [
'target_type' => 'user'
]
]);
$this->belongsTo('Groups', [
'foreignKey' => 'target_id',
'conditions' => [
'target_type' => 'group'
]
]);
With primaryKey id, adding and editing entities working, but editing makes dublicates, it's are not perfect for me. And in documentations use composite primaryKey, so i use ['target_id', 'target_type', 'section_id'], with it cake don't make dublicated, but aggain show me error: Cannot insert row, some of the primary key values are missing. Got (8, 197, ), expecting (target_id, section_id, target_type)

Controller doesn't get hasOne relationship data - Cakephp

I have a problem with related tables in CakePHP. I can't get the related table data include in the form.
I have two Entities. One of them is "Users" and the other one is "Subjects". Every User has a subject. Table "Subject" has foreign key idUser from Users table.
I added in UsersTable:
$this->hasOne('Subjects');
And I added in SubjectsTable:
$this->belongsTo('Users', [
'foreignKey' => 'idUser',
'joinType' => 'INNER'
]);
In the view (signup), I have this:
<div class="form-group">
<?php echo $this->Form->control('Subject.name',['label' => 'Asignatura','placeholder' => 'Ingrese asignatura','class' => 'form-control']) ?>
</div>
In the controller, I have this:
$user = $this->Users->patchEntity($user, $this->request->getData(),['associated' => 'Subjects']);
When I debug $user, I am getting this result:
\src\Controller\UsersController.php (line 113)
object(App\Model\Entity\User) {
'id' => '11111111',
'name' => 'Leo',
'firstlastname' => 'Messi',
'secondlastname' => 'Cuccittini',
'email' => 'leo.messi#gmail.com',
'password' => '$2y$10$E02nd/w89BDvgCyz36bQdeBbujOLrSdON1e6CD25aDYCP2VeLkNNm',
'role' => '2',
'[new]' => true,
'[accessible]' => [
'id' => true,
'name' => true,
'firstlastname' => true,
'secondlastname' => true,
'email' => true,
'password' => true,
'role' => true
],
'[dirty]' => [
'id' => true,
'name' => true,
'firstlastname' => true,
'secondlastname' => true,
'email' => true,
'password' => true,
'role' => true
],
'[original]' => [],
'[virtual]' => [],
'[hasErrors]' => false,
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Users'
}
So, I am not getting in the controller the data from Subject.
Any help, please.
Model
$this->hasOne('Subjects', [
'foreignKey' => 'userId'
]);
Controller:
$user = $this->User->get($id, ['contain' => ['Subjects']);
Entity/User.php
protected $_accessible = [
'subjects' => true
// ...
];
Form
https://book.cakephp.org/3.0/en/views/helpers/form.html#associated-form-inputs
Change: Subject.name to user.subject.name
<?php echo $this->Form->control('user.subject.name',['label' => 'Asignatura','placeholder' => 'Ingrese asignatura','class' => 'form-control']) ?>

saving model with deep association belonging to both higher models

I have three tables, Articles, Comments, and Tags.
Tags belong to both Articles and Comments.
$this->Articles->patchEntity($entity, $this->request->getData(), [
'associated' => ['Comments.Tags']
]);
with the following error:
SQLSTATE[HY000]: General error: 1364 Field 'article_id' doesn't have a default value
Please try correcting the issue for the following table aliases:
CommentsArticles
but if I save with only 'associated' => ['Comments'] it works saving the Article and Comments with join table associations, just doesn't save any Tags.
Articles table has these associations:
$this->hasMany('Tags', [
'foreignKey' => 'article_id'
]);
$this->belongsToMany('Comments', [
'foreignKey' => 'article_id',
'targetForeignKey' => 'comment_id',
'joinTable' => 'comments_articles'
]);
Comments table has these associations:
$this->hasMany('Tags', [
'foreignKey' => 'comment_id'
]);
$this->belongsToMany('Articles', [
'foreignKey' => 'comment_id',
'targetForeignKey' => 'article_id',
'joinTable' => 'comments_articles'
]);
and Tags table has these associations:
$this->belongsTo('Comments', [
'foreignKey' => 'comment_id',
'joinType' => 'INNER'
]);
$this->belongsTo('Articles', [
'foreignKey' => 'article_id',
'joinType' => 'INNER'
]);
This is the entity after patching looks like this.
object(App\Model\Entity\Article) {
'title' => 'example article name',
'users' => [
'_ids' => []
],
'comments' => [
(int) 0 => object(App\Model\Entity\Comment) {
'id' => (int) 1,
'content' => 'this is a comment',
'tags' => [
(int) 0 => object(App\Model\Entity\Tag) {
'name' => 'example tag name',
'[new]' => true,
'[accessible]' => [
'comment_id' => true,
'article_id' => true,
'comment' => true,
'article' => true
],
'[dirty]' => [
'name' => true
],
'[original]' => [],
'[virtual]' => [],
'[hasErrors]' => false,
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Tags'
}
],
'[new]' => false,
'[accessible]' => [
'content' => true,
'tags' => true,
'articles' => true
],
'[dirty]' => [
'tags' => true
],
'[original]' => [
'tags' => [
(int) 0 => [
'name' => '0'
]
]
],
'[virtual]' => [],
'[hasErrors]' => false,
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Comments'
}
],
'[new]' => true,
'[accessible]' => [
'title' => true,
'tags' => true,
'comments' => true,
'users' => true
],
'[dirty]' => [
'title' => true,
'users' => true,
'comments' => true
],
'[original]' => [
'users' => []
],
'[virtual]' => [],
'[hasErrors]' => false,
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Articles'
}
CaekPHP doesn't support that, it can only populate foreign keys of direct associations / in one direction. You could for example:
prepopulate the foreign key fields (which will of course only work when the article and/or comment already exists)
manually save the tags separately using the primary keys of the article and comment records
create association classes that pass the article primary key into the options when saving the article, and uses that to populate the article_id field when saving the tag
hook into the saving process on table level to pass on the article primary key and populate the tags with it
Here's a quick and dirty example for the latter solution, which should also give you an idea on how it could work on association level:
In ArticlesTable:
public function beforeSave(
\Cake\Event\Event $event,
\Cake\Datasource\EntityInterface $entity,
\ArrayObject $options
) {
if (isset($options['Articles.id'])) {
unset($options['Articles.id']);
}
}
protected function _onSaveSuccess($entity, $options)
{
if ($options['_primary']) {
$options['Articles.id'] = $entity->get('id');
}
return parent::_onSaveSuccess($entity, $options);
}
In TagsTable:
public function beforeSave(
\Cake\Event\Event $event,
\Cake\Datasource\EntityInterface $entity,
\ArrayObject $options
) {
if (!$options['_primary'] &&
isset($options['Articles.id'])
) {
$entity->set('article_id', $options['Articles.id']);
}
}

Deep associations in select query in cakephp3.7

I'm new to cakephp3. I'm unable to join associated tables data. I have
Employees Table.
EmployeeLogins Table
EmployeeCategories Table
Relation:
Employees table hasMany EmployeeLogins
And EmployeeLogins belognsTo EmployeeCategories
I'm using contain but not getting EmployeeCategories data.
The result i want is like
In single result set
Output :
array(
'Employees' => array(
'id' => 123,
),
'EmployeeLogin' => array(
[0] => array(
'employee_id' => 123,
'last_login' => '2019-01-01',
'category_id' => 3,
'EmployeeCategory' => array(
'id' => 3,
'category_name' => 'contract'
)
)
)
)
EmployeesTable.php
public function initialize(array $config)
{
parent::initialize($config);
$this->setTable('employees');
$this->setDisplayField('id');
$this->setPrimaryKey('id');
$this->addBehavior('Timestamp');
$this->hasMany('EmployeeLogins', [
'foreignKey' => 'user_id',
'dependent' => true
]);
}
EmployeeLoginsTable.php
public function initialize(array $config)
{
parent::initialize($config);
$this->setTable('employee_logins');
$this->setDisplayField('name');
$this->setPrimaryKey('id');
$this->belongsTo('Categories', [
'foreignKey' => 'category_id',
]);
}
EmployeeCategoriesTable.php
public function initialize(array $config)
{
parent::initialize($config);
$this->setTable('employee_catgories');
$this->setDisplayField('id');
$this->setPrimaryKey('id');
$this->addBehavior('Timestamp');
}
Code in Controller
$Employees = TableRegistry::get('Employees');
$EmployeeLogins = TableRegistry::get('EmployeeLogins');
$EmployeeCategories = TableRegistry::get('EmployeeCategories');
$Employees->hasMany('EmployeeLogins', [
'className' => 'EmployeeLogins',
'foreignKey' => 'employee_id',
'propertyName' => 'employee_logins'
]);
$Employees->EmployeeLogins->belongsTo('EmployeeCategories', [
'className' => 'EmployeeCategories',
'conditions' => [
'EmployeeLogins.category_id' => 'EmployeeCategories.id'
],
'propertyName' => 'employee_categores',
]);
$result = $Employees
->find()
->where([
'Employees.user_id)' => $user_id,
])
->contain([
'EmployeeLogins' => [
'EmployeeCategories'
]
])
->all();
You need to change your contain section like below
$result = $Employees
->find()
->where([
'Employees.user_id)' => $user_id,
])
->contain([
'EmployeeLogins', 'EmployeeLogins.EmployeeCategories'
])
->all();

record not found on contain model in CakePHP 3

I am using CakePHP 3.4
I am retrieving information of user like
$user = $this->Users->get($id, [
'contain' => [
'UserAddresses.States.Countries' => ['conditions' => [
'UserAddresses.deleted' => false]],
],
]);
Here, UserAddresses have user_id column and state_id column and States table have country_id column.
If there is no associated user_address in table, then I gives
record not found error
while removing States.Countries from contain works fine even when record does not exists in UserAddresses
Edit 2 : Relationships
UsersTable.php
$this->hasOne('UserAddresses', [
'foreignKey' => 'user_id'
]);
UserAddressesTable.php
$this->belongsTo('Users', [
'foreignKey' => 'user_id',
'joinType' => 'INNER'
]);
$this->belongsTo('States', [
'foreignKey' => 'state_id',
'joinType' => 'INNER'
]);
StatesTable.php
$this->belongsTo('Countries', [
'foreignKey' => 'country_id',
'joinType' => 'INNER'
]);
$this->hasMany('UserAddresses', [
'foreignKey' => 'state_id'
]);
CountriesTable.php
$this->hasMany('States', [
'foreignKey' => 'country_id'
]);
As Kilian Schuster said, your condition is being applied to Countries. I changed it, try the code bellow:
$user = $this->Users->get($id, [
'contain' => [
'UserAddresses' => [
'conditions' => [
'UserAddresses.deleted' => false
]
],
'UserAddresses.States.Countries'
]
]);
Edit: The record not found error could be caused by the Inner join type for Countries in States model if there is no address related to the got user. Change the join type to Left if the relationship is optional.
With this syntax, you are actually trying to apply the conditions to the "Countries" model, and not to the "UserAddresses" model.

Resources