CakePHP 3.4 如何插入一个属于和有很多关系
CakePHP 3.4 how to insert on a belongs to and has many relationship
在 cakePHP 3.4 上,我有 3 个 tables 属于并且有很多关系:Ingredients、Products 和 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');
}
}
我想要完成的是,当我插入一个新产品时,我还想插入 ingredient_id(s) 和与该产品相关的每种成分的字段数量,在 IngredientsProducts joiner table.
我一直在阅读食谱,发现在连接器 table 上保存附加数据时(在我的例子中,字段数量如下所述),你必须使用 _joinData 属性,所以我的添加视图如下所示:
<?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();
?>
在控制器上,添加方法如下所示:
$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']);
然而,当我提交时,它并没有保存任何东西。调试显示正在发布的以下内容:
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'
}
有没有人碰巧知道如何进行这项工作?
为了以防万一这里是 mySQL 上的 table 结构:
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;
如有任何帮助或指示,我们将不胜感激!
谢谢
保存失败时,查看errors
信息
每当保存实体不起作用时,检查 errors
信息:
'[errors]' => [
'name' => [
'_required' => 'This field is required'
]
],
您的验证规则根据需要定义了 Ingredients.name
字段,但它不存在于您的表单中,因此保存失败。
提供目标关联的主键
仔细查看文档中用于保存连接数据的示例,数据结构看起来与您的有所不同。
根据你对 ingredient_id
的使用,我怀疑你想 link 将产品添加到现有成分中,将 ingredient_id
放在 _joinData
中,但这不是这样的. Editing/linking 现有记录要求记录的主键出现在特殊的 _ids
键中,或者出现在目标关联 (Ingredients
) 的主键字段中。
所以在你想要存储额外连接数据的情况下,你必须使用 id
属性 作为成分,这样编组程序就知道它需要加载现有记录:
echo $this->Form->control('ingredients.0.id', [
// defining the type is required, as the input type
// guessing only recognizes `_ids` fields, or fields
// with `_id` appended as possible select types
'type' => 'select'
'options' => $ingredients
]);
echo $this->Form->control('ingredients.0._joinData.qty');
另见
在 cakePHP 3.4 上,我有 3 个 tables 属于并且有很多关系:Ingredients、Products 和 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');
}
}
我想要完成的是,当我插入一个新产品时,我还想插入 ingredient_id(s) 和与该产品相关的每种成分的字段数量,在 IngredientsProducts joiner table.
我一直在阅读食谱,发现在连接器 table 上保存附加数据时(在我的例子中,字段数量如下所述),你必须使用 _joinData 属性,所以我的添加视图如下所示:
<?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();
?>
在控制器上,添加方法如下所示:
$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']);
然而,当我提交时,它并没有保存任何东西。调试显示正在发布的以下内容:
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'
}
有没有人碰巧知道如何进行这项工作?
为了以防万一这里是 mySQL 上的 table 结构:
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;
如有任何帮助或指示,我们将不胜感激! 谢谢
保存失败时,查看errors
信息
每当保存实体不起作用时,检查 errors
信息:
'[errors]' => [
'name' => [
'_required' => 'This field is required'
]
],
您的验证规则根据需要定义了 Ingredients.name
字段,但它不存在于您的表单中,因此保存失败。
提供目标关联的主键
仔细查看文档中用于保存连接数据的示例,数据结构看起来与您的有所不同。
根据你对 ingredient_id
的使用,我怀疑你想 link 将产品添加到现有成分中,将 ingredient_id
放在 _joinData
中,但这不是这样的. Editing/linking 现有记录要求记录的主键出现在特殊的 _ids
键中,或者出现在目标关联 (Ingredients
) 的主键字段中。
所以在你想要存储额外连接数据的情况下,你必须使用 id
属性 作为成分,这样编组程序就知道它需要加载现有记录:
echo $this->Form->control('ingredients.0.id', [
// defining the type is required, as the input type
// guessing only recognizes `_ids` fields, or fields
// with `_id` appended as possible select types
'type' => 'select'
'options' => $ingredients
]);
echo $this->Form->control('ingredients.0._joinData.qty');