On cakePHP 3.4, i have 3 tables with a belongs to and has many relationship: Ingredients, Products and IngredientsProducts:
class IngredientsTable extends Table
{
public function initialize(array $config)
{
// Use through option because it looks like you
// have additional data on your IngredientsProducts table
$this->belongsToMany('Products', [
'through' => 'IngredientsProducts',
]);
}
}
class ProductsTable extends Table
{
public function initialize(array $config)
{
$this->belongsToMany('Ingredients', [
'through' => 'IngredientsProducts',
]);
}
}
class IngredientsProductsTable extends Table
{
public function initialize(array $config)
{
$this->belongsTo('Ingredients');
$this->belongsTo('Products');
}
}
What I want to accomplish is that when I insert a new product, I would like to insert also the ingredient_id(s) and field qty of each ingredient that is related to that product, on the IngredientsProducts joiner table.
I've been reading the cookbook, and saw that when saving aditional data on the joiner table (in my case the field qty as stated below), you have to use the _joinData property, so my add view looks like this:
<?php
$this->Form->create($product);
// fields of the Products table
echo $this->Form->control('name',array('class' => 'form-control'));
echo $this->Form->control('retail_price');
echo $this->Form->control('best_before');
echo $this->Form->control('comments');
// ingredient_id and qty fields of the ingredients_products table
echo $this->Form->control('ingredients.0._joinData.ingredient_id',['options' => $ingredients);
echo $this->Form->control('ingredients.0._joinData.qty');
//and repetition of these last two as ingredients.1._joinData to ingredients.N._joinData
$this->Form->button(__('Save'));
$this->Form->end();
?>
and on the controller the add method looks like this:
$product = $this->Products->newEntity();
if ($this->request->is('post')) {
$product = $this->Products->patchEntity($product, $this->request->getData(),[
'associated' => ['Ingredients._joinData']
]);
if ($this->Products->save($product)) {
$this->Flash->success(__('The product has been saved.'));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__('The product could not be saved. Please, try again.'));
}
$this->set(compact('product'));
$this->set('_serialize', ['product']);
However when I submit it doesn't save anything. The debug displays the following being posted:
object(App\Model\Entity\Product) {
'name' => 'salada',
'retail_price' => (float) 23,
'best_before' => (int) 234,
'comments' => 'wer',
'directions' => 'werwewerer',
'ingredients' => [
(int) 0 => object(App\Model\Entity\Ingredient) {
'_joinData' => object(Cake\ORM\Entity) {
'ingredient_id' => (int) 4,
'qty' => (float) 100,
'[new]' => true,
'[accessible]' => [
'*' => true
],
'[dirty]' => [
'ingredient_id' => true,
'qty' => true
],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'IngredientsProducts'
},
'[new]' => true,
'[accessible]' => [
'*' => true,
'id' => false
],
'[dirty]' => [
'_joinData' => true
],
'[original]' => [
'_joinData' => [
'ingredient_id' => '4',
'qty' => '100'
]
],
'[virtual]' => [],
'[errors]' => [
'name' => [
'_required' => 'This field is required'
]
],
'[invalid]' => [],
'[repository]' => 'Ingredients'
},
(int) 1 => object(App\Model\Entity\Ingredient) {
'_joinData' => object(Cake\ORM\Entity) {
'ingredient_id' => (int) 5,
'qty' => (float) 200,
'[new]' => true,
'[accessible]' => [
'*' => true
],
'[dirty]' => [
'ingredient_id' => true,
'qty' => true
],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'IngredientsProducts'
},
'[new]' => true,
'[accessible]' => [
'*' => true,
'id' => false
],
'[dirty]' => [
'_joinData' => true
],
'[original]' => [
'_joinData' => [
'ingredient_id' => '5',
'qty' => '200'
]
],
'[virtual]' => [],
'[errors]' => [
'name' => [
'_required' => 'This field is required'
]
],
'[invalid]' => [],
'[repository]' => 'Ingredients'
}
],
'[new]' => true,
'[accessible]' => [
'*' => true,
'id' => false
],
'[dirty]' => [
'name' => true,
'retail_price' => true,
'best_before' => true,
'comments' => true,
'directions' => true,
'ingredients' => true
],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Products'
}
Does anybody happen to know how to make this work?
just in case here are the table structures on mySQL:
TABLE `Ingredients` (
`id` int(11) NOT NULL,
`name` varchar(255) NOT NULL,
`category_id` int(11) NOT NULL,
`measure_id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Table products
TABLE `Products` (
`id` int(11) NOT NULL,
`name` varchar(255) NOT NULL,
`retail_price` float NOT NULL,
`best_before` int(11) NOT NULL,
`comments` text NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
TABLE `ingredients_products` (
`ingredient_id` int(11) NOT NULL,
`product_id` int(11) NOT NULL,
`qty` double NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Any help or directions would be kindly appreciated! Thanks