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)
Related
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.
Using PlumSearch plugin, it is mentioned in its documentation that we can modify 'label':
formConfig: Contains Form::input $options settings like class, input type, label name...
In my controller/initialize(), I need to change the label of some fields ("IP Address" instead of "Ip Adress", "Status" instead of "Asset Status"):
public function initialize()
{
parent::initialize();
$parameters = [
['name' => 'serial_number', 'className' => 'Input'],
['name' => 'model_number', 'className' => 'Input'],
['name' => 'ip_address', 'label' => 'IP Address', 'className' => 'Input'],
];
if ($this->request->param('action') == 'reportFacility') {
$statuses = $this->AssetsAssignations->AssetStatuses->find('list')->order(['name' => 'asc']);
$this->set(compact('asset_statuses'));
$parameters = [
['name' => 'asset_status_id', 'className' => 'Select', 'label' => 'Status',
'finder' => $statuses
],
];
} elseif ($this->request->param('action') == 'reportClient') {
$clients = $this->AssetsAssignations->Clients->find('list')->order(['last_name' => 'asc', 'first_name' => 'asc']);
$this->set(compact('clients'));
$parameters = [
['name' => 'client_id', 'className' => 'Select', 'label' => 'Client',
'finder' => $clients
],
];
} elseif ($this->request->param('action') == 'reportRoom') {
$rooms = $this->AssetsAssignations->Rooms->find('list')->order(['name' => 'asc']);
$this->set(compact('rooms'));
$parameters = [
['name' => 'room_id', 'className' => 'Select', 'label' => 'Room',
'finder' => $rooms
],
];
}
$this->loadComponent('PlumSearch.Filter', ['parameters' => $parameters]);
}`
The code above did not work for labels.
I was told to use the following code:
$inputOptions = [
'search' => [
'placeholder' => __('Type to search...'),
'class' => 'form-control',
'label' => 'Search'
]
];
$this->set(compact('inputOptions'));
but I failed to determine where and how in my code.
Any help please ?
simply you have to add it to the $parameters array this way
$parameters = [
/* other fields here */
[
'name' => 'ip_address',
'className' => 'Input',
'formConfig' => ['label' => 'IP Address']
],
];
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.
I have two tables seller_businesses and seller_business_categories. and their association is as follows
SellerBusinessesTable.php
$this->hasMany('SellerBusinessCategories', [
'foreignKey' => 'seller_business_id'
]);
SellerBusinessCategories.php
$this->belongsTo('SellerBusinesses', [
'foreignKey' => 'seller_business_id',
'joinType' => 'INNER'
]);
I'm using a single form to save data in both tables
<?= $this->Form->create($sellerBusiness, ['type' => 'file']) ?>
<?= $this->Form->input('company_name') ?>
<?= $this->Form->input('proof', ['type' => 'file']) ?>
<?= $this->Form->input('seller_business_categories._category_ids', ['multiple' => true, 'options' => $categories]) ?>
<?= $this->Form->button('submit', ['type' => 'submit']) ?>
<?= $this->Form->end() ?>
And controller action is
$sellerBusiness = $this->SellerBusinesses->newEntity();
if ($this->request->is('post')) {
$sellerBusiness->seller_id = $this->Auth->user('id');
$sellerBusiness = $this->SellerBusinesses->patchEntity($sellerBusiness, $this->request->data, [
'associated' => [
'SellerBusinessCategories'
]
]);
debug($sellerBusiness);
if ($save_s_b = $this->SellerBusinesses->save($sellerBusiness)) {
debug($save_s_b);
$this->Flash->success(__('The seller business has been saved.'));
return $this->redirect(['controller' => 'SellerBusinesses', 'action' => 'view', $save_s_b->id]);
} else {
$this->Flash->error(__('The seller business could not be saved. Please, try again.'));
}
}
But this is not saving record to seller_business_categories table.
From document Here
// Multiple select element for belongsToMany
echo $this->Form->input('tags._ids', [
'type' => 'select',
'multiple' => true,
'options' => $tagList,
]);
But this is not working. Is there any other way for hasMany
debug($this->request->data); gives
'seller_business_categories' => [
'_category_ids' => [
(int) 0 => '1',
(int) 1 => '2'
]
],
and debug($sellerBusiness); after patchEntity
object(App\Model\Entity\SellerBusiness) {
'seller_id' => (int) 16,
'company_name' => 'My company',
'seller_business_categories' => [
(int) 0 => object(App\Model\Entity\SellerBusinessCategory) {
(int) 0 => '1',
(int) 1 => '2',
'[new]' => true,
'[accessible]' => [
'*' => true
],
'[dirty]' => [
(int) 0 => true,
(int) 1 => true
],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'SellerBusinessCategories'
}
],
'[new]' => true,
'[accessible]' => [
'*' => true,
],
'[dirty]' => [
'seller_id' => true,
'company_name' => true,
'seller_business_categories' => true,
],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'SellerBusinesses'
}
and error
Error: SQLSTATE[HY000]:
General error: 1364 Field 'category_id' doesn't have a default value in seller_business_categories table
SellerBusinessesTable
$this->belongsToMany('Categories');
CategoriesTable
$this->belongsToMany('SellerBusinesses', [
'foreignKey' => 'category_id',
'targetForeignKey' => 'seller_business_id',
'joinTable' => 'categories_seller_businesses'
]);
// Pivot tables must be sorted alphabetically
bin/cake bake migration CreateCategoriesSellerBusinesses seller_business_id:integer category_id:integer created modified
CategoriesSellerBusinessesTable
$this->belongsTo('SellerBusinesses', [
'foreignKey' => 'seller_business_id',
'joinType' => 'INNER'
]);
$this->belongsTo('Categories', [
'foreignKey' => 'category_id',
'joinType' => 'INNER'
]);
Add.ctp
<?= $this->Form->create($sellerBusiness, ['type' => 'file']) ?>
...
<?= $this->Form->input('categories', ['type' => 'select', 'options' => $categories, 'multiple' => 'select', 'label' => __('Categories')]) ?>
...
<?= $this->Form->end() ?>
SellerBusinessesController
public function add()
{
$sellerBusiness = $this->SellerBusinesses->newEntity();
if ($this->request->is('post')) {
$sellerBusiness = $this->SellerBusinesses->patchEntity($sellerBusiness, $this->request->data);
$sellerBusiness->seller_id = $this->Auth->user('id');
if(isset($this->request->data['categories']))
{
$sellerBusiness -> categories = $this->SellerBusinesses->Categories->find()->where(['id IN' => $this->request->data['categories']])->all()->toArray();
}
if ($this->SellerBusinesses->save($sellerBusiness)) {
$this->Flash->success(__('The sellerBusiness has been saved.'));
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error(__('The seller could not be saved. Please, try again.'));
}
}
$categories = $this -> SellerBusinesses-> Categories-> find('treeList');
$this->set(compact('sellerBusiness', 'categories'));
$this->set('_serialize', ['sellerBusiness']);
I have scoured the internet and tried figuring this out with the docs, but I don't understand what I am doing wrong.
I have users that can have a membership and many orders. The membership and orders are also associated with a membership level. I am unsure if these associations are correct, but I think they are.
Here are my associations:
Users:
$this->hasOne('Memberships', [
'foreignKey' => 'user_id',
'joinType' => 'INNER'
]);
$this->hasMany('MembershipOrders', [
'foreignKey' => 'user_id',
'joinType' => 'INNER'
]);
Orders:
$this->belongsTo('Users', [
'foreignKey' => 'user_id',
'joinType' => 'INNER'
]);
$this->hasOne('MembershipLevels', [
'foreignKey' => 'membership_level_id',
'joinType' => 'INNER'
]);
Memberships:
$this->belongsTo('Users', [
'foreignKey' => 'user_id',
'joinType' => 'INNER'
]);
$this->hasOne('MembershipLevels', [
'foreignKey' => 'membership_level_id',
'joinType' => 'INNER'
]);
MembershipLevels:
$this->belongsToMany('MembershipOrders', [
'foreignKey' => 'membership_level_id',
'joinType' => 'INNER'
]);
$this->belongsToMany('Memberships', [
'foreignKey' => 'membership_level_id',
'joinType' => 'INNER'
]);
In my users controller I am trying to have a function that will add the user, a membership record, and an order for that user.
I am trying to make sure that validation errors are shown if any for the associated data in my form.
In the controller function I have:
public function checkout($id = null)
{
$user = $this->Users->newEntity($this->request->data(), [
'associated' => [
'MembershipOrders' => ['associated' => ['MembershipLevels']]
]
]);
$membershipLevel = $this->Users->Memberships->MembershipLevels->get($id);
if ( $this->request->is('post') ) {
$user = $this->Users->patchEntity( $user, $this->request->data(), [
'associated' => [
'MembershipOrders' => ['associated' => ['MembershipLevels']]
]
]);
if ( $this->Users->save($user, ['associated' => ['MembershipOrders' => ['associated' => ['MembershipLevels']]]]) ) {
$this->Flash->success(__('User has been added.'));
} else {
$this->Flash->error(__('User could not be added. Please, try again.'));
}
}
$this->set(compact('user', 'membershipLevel'));
$this->set('_serialize', ['user', 'membershipLevel']);
}
A simple form for my view is:
<?= $this->Form->create($user, ['id' => 'userForm']) ?>
<fieldset>
<legend><?= __('Primary Member') ?></legend>
<?= $this->Form->input('full_name', ['required' => false]) ?>
<?= $this->Form->input('username', ['required' => false]) ?>
<?= $this->Form->input('email', ['required' => false]) ?>
<?= $this->Form->input('password', ['required' => false]) ?>
<?= $this->Form->input('password_confirmation', ['type' => 'password', 'required' => false]) ?>
<?= $this->Form->input('specialty', ['required' => false]) ?>
<?= $this->Form->input('membership_orders.0.billing_name', ['label' => 'Name', 'data-stripe' => 'name', 'required' => false] ) ?>
<?= $this->Form->input('membership_orders.0.billing_street_1', ['label' => 'Address 1', 'required' => false] ) ?>
<?= $this->Form->input('membership_orders.0.billing_street_2', ['label' => 'Address 2', 'required' => false] ) ?>
<?= $this->Form->input('membership_orders.0.billing_city', ['label' => 'City', 'data-stripe' => 'address_city', 'required' => false] ) ?>
</fieldset>
<?= $this->Form->button(__('Join'), ['id' => 'submitBtn', 'class' => 'btn']) ?>
<?= $this->Form->end() ?>
I have tried MembershipOrders, membershipOrders, the current membership_orders, and all with and without the .0 in the form and cannot get any validation errors for the order information. The billing info is to be added to the orders table and the exact table name is "membership_orders".
Shouldn't cake be sending associated validation errors to my form as well?