使用 PHP 和 MySQL 从多维关联数组插入多个表
Inserting from a multidimensional associative array into multiple tables using PHP and MySQL
两天的大部分时间我都在做这个,但没有取得太大进展。我在这里和其他地方找到了大量帮助,但不太清楚如何让所有这些一起玩。
我正在为我在网上找到并想保存的食谱开发一个简单的数据库。
正在通过解析 URL 来获取配方详细信息然后进行一些手动修剪、添加和编辑来填充表单。每个食谱都有一些基本信息、一些成分和一组说明。这些进入三个不同的 tables 并且都通过 "recipe_id".
连接
我遇到的问题是我不知道如何从中获取数组:
将一些字段合并为一个 table 作为一行
将 3 部分成分放入另一个 table 中作为几行
最后指令进入第三个table作为几行。
这是来自表单的 $_POST:
array(47) {
["title"]=> string(33) "Hot and Fruity Caribbean Coleslaw"
["description"]=> string(11) "Lorem ipsum"
["credits"]=> string(11) "Lorem ipsum"
["url"]=> string(69) "http://thehappyfoodie.co.uk/recipes/hot-and-fruity-caribbean-coleslaw"
["category"]=> string(1) "1"
["cuisine"]=> string(1) "1"
["yield"]=> string(10) "8 servings"
["time_prep"]=> string(2) "10"
["time_cook"]=> string(2) "10"
["time_total"]=> string(2) "20"
["ingredient_quant_0"]=> string(0) ""
["ingredient_uom_0"]=> string(1) "8"
["ingredient_0"]=> string(17) "1/2 Savoy cabbage"
["ingredient_quant_1"]=> string(0) ""
["ingredient_uom_1"]=> string(2) "11"
["ingredient_1"]=> string(17) "1/2 white cabbage"
["ingredient_quant_2"]=> string(0) ""
["ingredient_uom_2"]=> string(1) "-"
["ingredient_2"]=> string(21) "1/2 red onion, peeled"
["ingredient_quant_3"]=> string(0) ""
["ingredient_uom_3"]=> string(1) "8"
["ingredient_3"]=> string(15) "1/2 small mango"
["ingredient_quant_4"]=> string(0) ""
["ingredient_uom_4"]=> string(1) "-"
["ingredient_4"]=> string(20) "3 tsp French mustard"
["ingredient_quant_5"]=> string(0) ""
["ingredient_uom_5"]=> string(1) "-"
["ingredient_5"]=> string(19) "100ml cider vinegar"
["ingredient_quant_6"]=> string(0) ""
["ingredient_uom_6"]=> string(1) "-"
["ingredient_6"]=> string(29) "8 tbsp soft light brown sugar"
["ingredient_quant_7"]=> string(3) "100"
["ingredient_uom_7"]=> string(2) "10"
["ingredient_7"]=> string(15) "100ml olive oil"
["ingredient_quant_8"]=> string(0) ""
["ingredient_uom_8"]=> string(1) "-"
["ingredient_8"]=> string(15) "Salt and pepper"
["ingredient_quant_9"]=> string(1) "1"
["ingredient_uom_9"]=> string(1) "9"
["ingredient_9"]=> string(54) "1/2 tbsp X Hot Reggae Reggae Sauce or hot chilli sauce"
["ingredient_quant_10"]=> string(0) ""
["ingredient_uom_10"]=> string(1) "-"
["ingredient_10"]=> string(48) "2 red chillies, seeded and cut into fine slivers"
["instruction_0"]=> string(177) "Remove and discard the cabbage cores and finely shred the leaves. Slice the onion wafer-thin using a mandolin if you have one. Peel the mango and cut the flesh into matchsticks."
["instruction_1"]=> string(265) "Put the mustard, vinegar and sugar in a jam jar. Screw on the lid and give it a good shake. Add the oil, salt, pepper and hot sauce. Shake again then poor into a large serving bowl. Toss in the cabbage, onion, mango and chillies and mix well. Taste for seasoning."
["image"]=> string(127) "https://flockler.com/thumbs/sites/192/127_grillitlevi_hotandfruitycoleslaw-smaller_s1200x630_c1500x876_l0x482_q80_noupscale.jpg"
然后我将该数组传递给一个函数并尝试将其分解为应该进入不同 tables 的部分:
function addnewrecipe($postArray) {
var_dump($postArray);
// Test and clean user input
$cleanedArray = array();
foreach ($postArray as $postKey => $postValue) {
$cleanValue = test_input($postArray[$postKey]);
$cleanedArray[$postKey] = $cleanValue;
}
// Map form post names to those in the DB
$mappingArray = array(
'title' => 'name',
'description' => 'description',
'credits' => 'author',
'url' => 'url',
'category' => 'category_id',
'cuisine' => 'cuisine_id',
'yield' => 'yield',
'time_prep' => 'preptime',
'time_cook' => 'cooktime',
'time_total' => 'totaltime',
'image' => 'image'
);
// Create a final array with used form fields and clean input
$finalArray = array();
foreach($mappingArray as $formKey => $dbKey) {
if(!empty($cleanedArray[$formKey])) {
$finalArray[$dbKey] = $cleanedArray[$formKey];
}
}
//Connect to DB
$conn = connDB();
// Begin transaction
try {
$conn->autocommit(FALSE);
$recipeKey = array_keys($finalArray);
$recipeValue = array_values($finalArray);
$query = "INSERT INTO recipes (" . implode(', ', $recipeKey) . ") " . "VALUES ('" . implode("', '", $recipeValue) . "')";
//echo $query;
$result = $conn->query($query);
if ( !$result ) {
$result->free();
throw new Exception($conn->error);
}
$recipe_id = $conn->insert_id; // last auto_inc id from *this* connection
//$query = "INSERT INTO ingredients (recipe_id,ingredient,uom_id,ingredient_quant) ";
//$query .= "VALUES ('$recipe_id','$ingredient')";
//$result = $conn->query($query);
//if ( !$result ) {
// $result->free();
// throw new Exception($conn->error);
//}
$conn->commit();
$conn->autocommit(TRUE); // i.e., end transaction
}
catch ( Exception $e ) {
$conn->rollback();
$conn->autocommit(TRUE); // i.e., end transaction
}
$conn->close();
它的基本信息工作正常,虽然我觉得我把它稍微复杂化了一点。我首先检查输入是否存在不安全的东西,然后将表单中的 key/column 名称重新映射到数据库中的名称,并创建一个新数组 $finalArray
,结果干净,省略了说明和成分。
然后进入标准的 INSERT 语句,我可以继续准备插入成分和说明。但这就是我让自己感到困惑的地方。
每个食谱都会有不同数量的成分。每个成分都有三个值,其中两个可以为 NULL。它们将被前一个插入中的 "recipe_id" 引用,它像这样工作得很好: $recipe_id = $conn->insert_id;
但是我如何获得每种成分的三个值并将它们作为一行插入?我试过了
$ingredientArray = array();
$i = 0;
while ($i < 5) {
if (isset($cleanedArray["ingredient_" . $i])) {
$ingredientArray["ingredient_" . $i] = $cleanedArray["ingredient_" . $i];
}
if (isset($cleanedArray["uom_id_" . $i])) {
$ingredientArray["uom_id_" . $i] = $cleanedArray["uom_id_" . $i];
}
if (isset($cleanedArray["ingredient_quant_" . $i])) {
$ingredientArray["ingredient_quant_" . $i] = $cleanedArray["ingredient_quant_" . $i];
}
$i++;
}
//var_dump($ingredientArray);
把它们弄出来,但不知道可能有多少,我想这种方法很值得怀疑。
我觉得这不应该那么难。我有一个相当简单的数组,其中包含值以及拆分该数组并将其插入正确的 table 的看似简单的任务。非常感谢任何关于如何解决这个问题的帮助!
$ingredientArray = [];
$i = 0;
while ($i < 5) {
$ingredientArray[] = [
'name' => isset($cleanedArray["ingredient_" . $i]) ? $cleanedArray["ingredient_" . $i] : null,
'quantity' => isset($cleanedArray["ingredient_quantity_" . $i]) ? $cleanedArray["ingredient_quantity_" . $i] : null
// etc.
];
}
而不是像您现在这样依靠字符串操作来确定哪种成分属于哪个字段:
array(
// .... some other stuff above
"ingredient_quant_0" => ""
"ingredient_uom_0" => "8" ,
"ingredient_0" => "1/2 Savoy cabbage" ,
"ingredient_quant_1" => "blah" ,
"ingredient_uom_1" => "11" ,
"ingredient_1" => "1/2 Ricotta Cheese" ,
"ingredient_quant_2" => "" ,
"ingredient_uom_2" => "12" ,
"ingredient_2" => "2 Chilis" ,
)
构建您的 post 数据,使成分像这样分组在一起:
array(
// .... some other stuff above
"ingredients" => array(
[0] => array( "quant" => "", "uom" => "8", "ingredient" => "1/2 Savoy cabbage"),
[1] => array( "quant" => "blah", "uom" => "11", "ingredient" => "1/2 Ricotta Cheese"),
[2] => array( "quant" => "", "uom" => "12", "ingredient" => "2 Chilis"),
)
)
HTML 会是这样的:
<input type="text" name="ingredients[0]['ingredient']>
<input type="text" name="ingredients[0]['uom']>
<input type="text" name="ingredients[0]['quant']>
<hr>
<input type="text" name="ingredients[1]['ingredient']>
...
然后您可以更轻松地构建插入语句
<?php
$recipe_id = $conn->insert_id; // last auto_inc id from *this* connection
foreach($myPostArray['ingredients'] as $ingredient){
$query .= "INSERT INTO ingredients (recipe_id,ingredient,uom_id,ingredient_quant) ";
$query .= "VALUES ( $recipe_id, {$ingredient['ingredient']}, {$ingredient['uom']}, {$ingredient['quant']})";
}
$result = $conn->query($query);
两天的大部分时间我都在做这个,但没有取得太大进展。我在这里和其他地方找到了大量帮助,但不太清楚如何让所有这些一起玩。
我正在为我在网上找到并想保存的食谱开发一个简单的数据库。
正在通过解析 URL 来获取配方详细信息然后进行一些手动修剪、添加和编辑来填充表单。每个食谱都有一些基本信息、一些成分和一组说明。这些进入三个不同的 tables 并且都通过 "recipe_id".
连接我遇到的问题是我不知道如何从中获取数组:
将一些字段合并为一个 table 作为一行
将 3 部分成分放入另一个 table 中作为几行
最后指令进入第三个table作为几行。
这是来自表单的 $_POST:
array(47) {
["title"]=> string(33) "Hot and Fruity Caribbean Coleslaw"
["description"]=> string(11) "Lorem ipsum"
["credits"]=> string(11) "Lorem ipsum"
["url"]=> string(69) "http://thehappyfoodie.co.uk/recipes/hot-and-fruity-caribbean-coleslaw"
["category"]=> string(1) "1"
["cuisine"]=> string(1) "1"
["yield"]=> string(10) "8 servings"
["time_prep"]=> string(2) "10"
["time_cook"]=> string(2) "10"
["time_total"]=> string(2) "20"
["ingredient_quant_0"]=> string(0) ""
["ingredient_uom_0"]=> string(1) "8"
["ingredient_0"]=> string(17) "1/2 Savoy cabbage"
["ingredient_quant_1"]=> string(0) ""
["ingredient_uom_1"]=> string(2) "11"
["ingredient_1"]=> string(17) "1/2 white cabbage"
["ingredient_quant_2"]=> string(0) ""
["ingredient_uom_2"]=> string(1) "-"
["ingredient_2"]=> string(21) "1/2 red onion, peeled"
["ingredient_quant_3"]=> string(0) ""
["ingredient_uom_3"]=> string(1) "8"
["ingredient_3"]=> string(15) "1/2 small mango"
["ingredient_quant_4"]=> string(0) ""
["ingredient_uom_4"]=> string(1) "-"
["ingredient_4"]=> string(20) "3 tsp French mustard"
["ingredient_quant_5"]=> string(0) ""
["ingredient_uom_5"]=> string(1) "-"
["ingredient_5"]=> string(19) "100ml cider vinegar"
["ingredient_quant_6"]=> string(0) ""
["ingredient_uom_6"]=> string(1) "-"
["ingredient_6"]=> string(29) "8 tbsp soft light brown sugar"
["ingredient_quant_7"]=> string(3) "100"
["ingredient_uom_7"]=> string(2) "10"
["ingredient_7"]=> string(15) "100ml olive oil"
["ingredient_quant_8"]=> string(0) ""
["ingredient_uom_8"]=> string(1) "-"
["ingredient_8"]=> string(15) "Salt and pepper"
["ingredient_quant_9"]=> string(1) "1"
["ingredient_uom_9"]=> string(1) "9"
["ingredient_9"]=> string(54) "1/2 tbsp X Hot Reggae Reggae Sauce or hot chilli sauce"
["ingredient_quant_10"]=> string(0) ""
["ingredient_uom_10"]=> string(1) "-"
["ingredient_10"]=> string(48) "2 red chillies, seeded and cut into fine slivers"
["instruction_0"]=> string(177) "Remove and discard the cabbage cores and finely shred the leaves. Slice the onion wafer-thin using a mandolin if you have one. Peel the mango and cut the flesh into matchsticks."
["instruction_1"]=> string(265) "Put the mustard, vinegar and sugar in a jam jar. Screw on the lid and give it a good shake. Add the oil, salt, pepper and hot sauce. Shake again then poor into a large serving bowl. Toss in the cabbage, onion, mango and chillies and mix well. Taste for seasoning."
["image"]=> string(127) "https://flockler.com/thumbs/sites/192/127_grillitlevi_hotandfruitycoleslaw-smaller_s1200x630_c1500x876_l0x482_q80_noupscale.jpg"
然后我将该数组传递给一个函数并尝试将其分解为应该进入不同 tables 的部分:
function addnewrecipe($postArray) {
var_dump($postArray);
// Test and clean user input
$cleanedArray = array();
foreach ($postArray as $postKey => $postValue) {
$cleanValue = test_input($postArray[$postKey]);
$cleanedArray[$postKey] = $cleanValue;
}
// Map form post names to those in the DB
$mappingArray = array(
'title' => 'name',
'description' => 'description',
'credits' => 'author',
'url' => 'url',
'category' => 'category_id',
'cuisine' => 'cuisine_id',
'yield' => 'yield',
'time_prep' => 'preptime',
'time_cook' => 'cooktime',
'time_total' => 'totaltime',
'image' => 'image'
);
// Create a final array with used form fields and clean input
$finalArray = array();
foreach($mappingArray as $formKey => $dbKey) {
if(!empty($cleanedArray[$formKey])) {
$finalArray[$dbKey] = $cleanedArray[$formKey];
}
}
//Connect to DB
$conn = connDB();
// Begin transaction
try {
$conn->autocommit(FALSE);
$recipeKey = array_keys($finalArray);
$recipeValue = array_values($finalArray);
$query = "INSERT INTO recipes (" . implode(', ', $recipeKey) . ") " . "VALUES ('" . implode("', '", $recipeValue) . "')";
//echo $query;
$result = $conn->query($query);
if ( !$result ) {
$result->free();
throw new Exception($conn->error);
}
$recipe_id = $conn->insert_id; // last auto_inc id from *this* connection
//$query = "INSERT INTO ingredients (recipe_id,ingredient,uom_id,ingredient_quant) ";
//$query .= "VALUES ('$recipe_id','$ingredient')";
//$result = $conn->query($query);
//if ( !$result ) {
// $result->free();
// throw new Exception($conn->error);
//}
$conn->commit();
$conn->autocommit(TRUE); // i.e., end transaction
}
catch ( Exception $e ) {
$conn->rollback();
$conn->autocommit(TRUE); // i.e., end transaction
}
$conn->close();
它的基本信息工作正常,虽然我觉得我把它稍微复杂化了一点。我首先检查输入是否存在不安全的东西,然后将表单中的 key/column 名称重新映射到数据库中的名称,并创建一个新数组 $finalArray
,结果干净,省略了说明和成分。
然后进入标准的 INSERT 语句,我可以继续准备插入成分和说明。但这就是我让自己感到困惑的地方。
每个食谱都会有不同数量的成分。每个成分都有三个值,其中两个可以为 NULL。它们将被前一个插入中的 "recipe_id" 引用,它像这样工作得很好: $recipe_id = $conn->insert_id;
但是我如何获得每种成分的三个值并将它们作为一行插入?我试过了
$ingredientArray = array();
$i = 0;
while ($i < 5) {
if (isset($cleanedArray["ingredient_" . $i])) {
$ingredientArray["ingredient_" . $i] = $cleanedArray["ingredient_" . $i];
}
if (isset($cleanedArray["uom_id_" . $i])) {
$ingredientArray["uom_id_" . $i] = $cleanedArray["uom_id_" . $i];
}
if (isset($cleanedArray["ingredient_quant_" . $i])) {
$ingredientArray["ingredient_quant_" . $i] = $cleanedArray["ingredient_quant_" . $i];
}
$i++;
}
//var_dump($ingredientArray);
把它们弄出来,但不知道可能有多少,我想这种方法很值得怀疑。
我觉得这不应该那么难。我有一个相当简单的数组,其中包含值以及拆分该数组并将其插入正确的 table 的看似简单的任务。非常感谢任何关于如何解决这个问题的帮助!
$ingredientArray = [];
$i = 0;
while ($i < 5) {
$ingredientArray[] = [
'name' => isset($cleanedArray["ingredient_" . $i]) ? $cleanedArray["ingredient_" . $i] : null,
'quantity' => isset($cleanedArray["ingredient_quantity_" . $i]) ? $cleanedArray["ingredient_quantity_" . $i] : null
// etc.
];
}
而不是像您现在这样依靠字符串操作来确定哪种成分属于哪个字段:
array(
// .... some other stuff above
"ingredient_quant_0" => ""
"ingredient_uom_0" => "8" ,
"ingredient_0" => "1/2 Savoy cabbage" ,
"ingredient_quant_1" => "blah" ,
"ingredient_uom_1" => "11" ,
"ingredient_1" => "1/2 Ricotta Cheese" ,
"ingredient_quant_2" => "" ,
"ingredient_uom_2" => "12" ,
"ingredient_2" => "2 Chilis" ,
)
构建您的 post 数据,使成分像这样分组在一起:
array(
// .... some other stuff above
"ingredients" => array(
[0] => array( "quant" => "", "uom" => "8", "ingredient" => "1/2 Savoy cabbage"),
[1] => array( "quant" => "blah", "uom" => "11", "ingredient" => "1/2 Ricotta Cheese"),
[2] => array( "quant" => "", "uom" => "12", "ingredient" => "2 Chilis"),
)
)
HTML 会是这样的:
<input type="text" name="ingredients[0]['ingredient']>
<input type="text" name="ingredients[0]['uom']>
<input type="text" name="ingredients[0]['quant']>
<hr>
<input type="text" name="ingredients[1]['ingredient']>
...
然后您可以更轻松地构建插入语句
<?php
$recipe_id = $conn->insert_id; // last auto_inc id from *this* connection
foreach($myPostArray['ingredients'] as $ingredient){
$query .= "INSERT INTO ingredients (recipe_id,ingredient,uom_id,ingredient_quant) ";
$query .= "VALUES ( $recipe_id, {$ingredient['ingredient']}, {$ingredient['uom']}, {$ingredient['quant']})";
}
$result = $conn->query($query);