multiple select for hasMany association in CakePHP 3 - cakephp

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']);

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']) ?>

CakePHP 3: issue saving hasMany associations

I'm having trouble saving and updating hasMany associations. It seems that Cake can't patch the entity correctly somehow.
ProductGroups Table:
$this->hasMany('ProductIdentities', [
'foreignKey' => 'product_group_id',
'saveStrategy' => 'replace'
]);
ProductIdentities Table:
$this->belongsTo('ProductGroups', [
'foreignKey' => 'product_group_id'
]);
ProductGroupsController:
// patch entity
$productGroup = $this->ProductGroups->patchEntity($productGroup, $this->request->data, [
'associated' => [
'StaffMembers' => ['onlyIds' => true],
'ProductIdentities' => ['onlyIds' => true]
]
]);
$this->request->data:
[
'group_name' => 'Creative and Performing Arts',
'active' => '1',
'product_type_id' => '2',
'staff_members' => [
'_ids' => [
(int) 0 => '103',
(int) 1 => '11',
(int) 2 => '3'
]
],
'product_identities' => [
'_ids' => [
(int) 0 => '1760',
(int) 1 => '1762',
(int) 2 => '1763',
(int) 3 => '1764'
]
]
]
edit.ctp
<?php
echo $this->Form->input('group_name',
['class' => 'form-control']);
echo $this->Form->input('active',
['class' => 'form-control']);
echo $this->Form->input('product_type_id',
['class' => 'form-control']);
echo $this->Form->input('staff_members._ids',
['options' => $staffMembers,
'class' => 'form-control height-200']);
echo $this->Form->input('product_identities._ids',
['options' => $productIdentities,
'class' => 'form-control height-500']);
?>
If a productGroup is not associated with any productIdentities, it saves fine. However if you want to select more productIdentities or unselect some existing ones, the data won't be saved. Instead, Cake will create new records in product_identites table.
After doing a debug, I could see that Cake did not patch entity correctly. See below:
'product_identities' => [
(int) 0 => object(App\Model\Entity\ProductIdentity) {
(int) 0 => '1760',
(int) 1 => '1762',
(int) 2 => '1763',
(int) 3 => '1764',
'[new]' => true,
'[accessible]' => [
'*' => true
],
'[dirty]' => [
(int) 0 => true,
(int) 1 => true,
(int) 2 => true,
(int) 3 => true
],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'ProductIdentities'
}
],
The onlyIds option is supposed to stop Cake from creating new records but obviously it didn't work.
And I've formatted my data into the format suggested in Cake's documentation so I'm very confused.
$data = [
'title' => 'My new article',
'body' => 'The text',
'user_id' => 1,
'comments' => [
'_ids' => [1, 2, 3, 4]
]
];
http://book.cakephp.org/3.0/en/orm/saving-data.html#converting-hasmany-data
Any comments/help is appreciated.

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.

Adding user and associated data CakePhp 3.x and receive validation errors for associated data

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?

Resources