2 回答

TA貢獻1848條經驗 獲得超2個贊
這里有很多錯誤,其中大部分可以通過檢查您的數據來解決。利用var_dump并print_r確保變量包含您認為的內容。
首先,如果您為數據庫列分配別名,則它只是一列。所以你最終得到數組索引CodUso1,CodUso2等到CodUso9,然后categories作為 . 的別名CodUso10。其次,您嘗試循環通過$result["categories"]which 不存在,因為fetchAll將返回一個索引數組。您可以通過使用print_r($result);并查看您正在使用的內容來實現這兩者。第三,您將用戶提供的數據直接傳遞到數據庫查詢中,這是讓您的數據庫受到攻擊的好方法。
試試這個。我們安全地準備一個語句來檢索所有十個類別列,然后一次循環遍歷它們,執行第二個準備好的語句以獲取結果。請注意,除了安全性之外,準備好的語句的好處之一是在重復執行相同的查詢時減少了開銷。最后,盡可能將代碼和演示文稿分開。在循環中間將 HTML 轉儲到屏幕是丑陋且難以使用的。您應該返回一個 JSON 對象,然后使用您的 Javascript 回調來構建元素。
<?php
$car_model = $_POST['get_car'];
// prepare the first query
$query = "SELECT CodUso1, CodUso2, CodUso3, CodUso4, CodUso5,
CodUso6, CodUso7, CodUso8, CodUso9, CodUso10
FROM cars WHERE car_model = ? LIMIT 1";
$stmt = $pdo->prepare($query);
$stmt->execute([$car_model]);
// there's only one item, no loop needed
$categories = $stmt->fetch(\PDO::FETCH_ASSOC);
// here we prepare the second query
$query = "SELECT description FROM categories WHERE code = ?";
$stmt = $pdo->prepare($query);
// bind the variable to the ? parameter
$stmt->bindParam(1, $c);
$options = [];
foreach ($categories as $c) {
if ($c == 0) {
continue;
}
$stmt->execute();
// we can fetch the single column directly
$description = $stmt->fetchColumn();
$options[] = ["id"=>$c, "description"=>$description];
}
header("Content-Type: application/json");
echo json_encode($options);
然后在你的 Javascript 回調中,做這樣的事情。我假設您使用的是 jQuery:
...
success: function(data, status, xhr) {
// erase existing values
$("select[name='category']").html("");
// jQuery will turn this into an object automatically
// loop through it and append an option element for each item
data.each(function(v) {
var sel = $("<option>").val(v.id).html(v.description);
$("select[name='category']").append(sel);
});
}

TA貢獻1856條經驗 獲得超17個贊
不工作的原因foreach是因為$result['categories']它不是一個數組。您的查詢select子句只是重命名CodUse10為categories.
SELECT CodUso1,
CodUso2,
CodUso3,
CodUso4,
CodUso5,
CodUso6,
CodUso7,
CodUso8,
CodUso9,
CodUso10 AS categories
但真正的問題遠不止于此。它回到你的表模式。任何時候你有諸如 field1、field2、field3 之類的東西……你幾乎可以肯定有一個未規范化的表。正確的架構看起來像這樣:
Car Car_Category Category
id car_id id
model category_id description
當您想獲取某輛車的類別列表時,只需查詢連接表:
select c.model, cat.id, cat.description
from car c
inner join car_category cc on c.id=cc.car_id
inner join category cat on cc.category_id=cat.id
where car.id=?
我不完全理解您是否嘗試顯示可用選項或選定選項,但無論哪種方式,都將使用相同類型的多對多連接。因此,car_category您可能有一個名為的表available_options和另一個名為selected_options.
...但是我不能更改數據庫!
在這種情況下,將沒有“正確”的解決方案;只是一些創造性的方法來解決它。目標應該是盡量減少產生的技術債務??赡茏畲蟮牟糠质菍⒛P停ㄟ壿嫞┡c視圖(html)分開。這樣,如果/當架構被更正時,您不必在更改訪問方法時深入視圖并破壞事物;您所要做的就是插入一個不同的類或函數來獲取信息并以相同的方式輸出。
定義視圖期望如何接收模型的數據
在開始使用模型之前,我需要知道視圖將如何使用它。對于我自己的應用程序,我有一個類可以為我格式化輸入、下拉菜單和復選框,ala ruby on rails:
<div class="form-group">
<label for="category">Category</label>
<?= FormDecorator::showAsDropDown($optionList, $defaultOption,['id'=>'category','name'=>'category','class'=>'form-control', etc...]) ?>
</div>
要使用它,我將提供一個關聯數組,其中 options = array('value'=>'description')。關鍵是我需要模型來提供該數組,但是它可能會獲取信息。但模型不負責創建任何html。
使用相同的計劃,您的輸出可能看起來像
<div class="form-group row">
<label class="col-sm-2 form-control-label">Category</label>
<div class="col-sm-4">
<select class="form-control" name="category">
<option disabled selected hidden>Select a car first...</option>
<?php foreach($options as $value => $description): ?>
<option value="<?= $value ?>"><?= $description ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
創建模型以提供該數據
通常,我會使用一個對象,因為我使用自己的 MVC 框架。但為了簡單起見,我將使用一個普通的舊函數(但我強烈建議使用類,因為它們更加靈活,并且方法名稱在類的范圍內,而不是全局范圍內)
一次查找描述
您想要遍歷 10 個不同字段的結果,所有字段都命名為CodUso{$number}.
首先,創建一個函數來檢索原始數據:
function getCategoriesFor($car_model) {
global $pdo; // ick, a class would avoid globals.
$query =<<<CATEGORYQUERY
SELECT CodUso1, CodUso2, CodUso3, CodUso4, CodUso5,
CodUso6, CodUso7, CodUso8, CodUso9, CodUso10
FROM cars
WHERE car_model = ?
CATEGORYQUERY;
$stmt = $pdo->prepare($query);
$stmt->execute($car_model);
return stmt->fetch(\PDO::FETCH_ASSOC);
}
現在,創建一個函數來獲取類別的描述:
// if this were an object, I would call it $Category->find($id)
function getCategoryDescriptionOf($code) {
global $pdo;
$query = "select * from categories where code=?";
$stmt = $pdo->prepare($query);
$stmt->execute($id);
return $stmt->fetchAll();
}
然后創建一個函數來遍歷可用的選項:
function getCategoryOptionsByModel($car_model) {
// get the row containing CodUso1 ... CodUso10
$categoryRow = getCategoriesFor($car_model);
// always initialize output before generating its contents
$out = [];
// 10 fields, iterate through them. This is the hacky part...
for($i=1; $i <= 10; $i++) {
// generate the field name
$field = 'CodUso' . $i;
// get the code from the car_model table row
$code = $categoryRow[$field];
// format the array we will use in the view
$out[$code] = getCategoryDescriptionOf($code);
}
return $out; // [code => description]
}
哇!現在剩下的就是在視圖中使用它:
<?php
$car_model = $_GET['car_model']; // or however it is assigned...
?>
<html>
... snip ...
<div class="form-group row">
<label class="col-sm-2 form-control-label">Category</label>
<div class="col-sm-4">
<select class="form-control" name="category">
<option disabled selected hidden>Select a car first...</option>
<?php foreach( getCategoryOptionsByModel($car_model) as $value => $description): ?>
<option value="<?= $value ?>"><?= $description ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
歡呼!我標準化了表格!
如果您對表進行規范化,只需編寫一個新函數來替換當前getCategoriesFor()函數(根據需要替換真實字段名稱)并在視圖中使用它,而不是getCategoryOptionsByModel($car_model)或者只是更改 getCategoryOptionsByModel($car_model) 以返回 getCategoriesFor($car_model):
function getCategoriesFor($car_model) {
global $pdo;
$query =<<<THISISHOWITSHOULDBEDONEQUERY
select cat.code, cat.description
from cars c
inner join car_category cc on c.id=cc.car_id
inner join category cat on cc.category_id=cat.id
where cars.car_model=?
THISISHOWITSHOULDBEDONEQUERY;
$stmt = $pdo->prepare($query)->execute($car_model);
$out = [];
foreach($stmt as $row) {
$code = $row['code'];
$description = $row['description'];
$out[$code] = $description;
}
return $out;
}
好處
通過將邏輯與表示分離,并確保每個函數只做一件小事,您現在可以更輕松地更改數據的編譯方式。除了命名不同的數據源之外,您不必對視圖進行任何更改。如果你之后的下一個程序員是一個知道你住在哪里的殺人狂,你會安全得多!
免責聲明
這一切都在我的腦海中。雖然我推薦 PDO,但我既不使用 MySQL 也不使用 PDO,我的用法可能需要更正。
- 2 回答
- 0 關注
- 193 瀏覽
添加回答
舉報