我在找到更新现有记录时如何正确设置准备好的PDO SQL语句时迷失了方法。
我的数组传递给我的方法是这样的:
array(9) { ["catName"]=> string(10) "Kato Marks" ["age"]=> string(2) "40" ["gender"]=> string(6) "Female" ["createTime"]=> string(19) "2017-10-03 03:55:39" ["coloring"]=> string(5) "Black" ["hairLength"]=> string(5) "Short" ["currentMood"]=> string(5) "rowdy" ["weight"]=> string(2) "17" ["hasCatittude"]=> string(1) "0" }
with key是数据库表列,值是我想要更新的数据库值
到目前为止,我有以下内容:
public function updateRow($data, $catID)
{
$db = self::getConnection();
try
{
$stmt = $db->prepare("UPDATE users SET " . implode('= ', array_keys($data). array_values($data)). " WHERE id='{$catID}'");
foreach($data as $key => $value) {
$stmt->bindValue($key, $value, PDO::PARAM_STR);
}
$stmt->execute();
} catch (\PDOException $e) {
return 'Adding new record failed' . $e->getMessage();
}
}
但是当我将语句print_r到屏幕时,我得到以下内容:
PDOStatement Object ( [queryString] => UPDATE users SET WHERE id='108' )
我无法弄清楚如何正确编写准备好的语句,我动态地将表名设置为数组键等,任何帮助都将非常感谢。
答案 0 :(得分:1)
从您的评论中,此函数属于Database
类。不可否认,此类可以在任何表上使用,以根据任何条件更新任何行。但是,查看函数签名,我们可以看到它应该接受$catId
参数,这意味着它将在非常特定的表上使用,使用特定列过滤行。
你可以通过简单地重命名函数和参数来更好地代表它实际在做什么,但仍然无法解决我认为问题的核心:对象有太多的责任。
根据Single Responsibility Principle,一个班级"应该有一个,只有一个,有理由被改变"。在这种情况下,如果将一列添加到User
表中,或者需要将另一列添加到WHERE
子句中,则只应影响User
类(或实体)虽然Database
类不需要任何更改。
为了简单起见,让我们设想一个fridge
数据库,其中有一个名为fruits
的表(我知道,非常富有想象力)。
create table fruits (
id int not null auto_increment,
name varchar(20),
color varchar(20),
weight int,
order int, /* order of appearance, say, for a list */
PRIMARY KEY (id)
);
这个表的php表示可能看起来有点像
class Fruit {
private $id;
private $name;
private $color;
private $weight;
private $order;
public function __construct($id, $name, $color, $weight) {
$this->id = $id;
$this->name = $name;
$this->color = $color;
$this->weight = $weight;
$this->order = $order;
}
}
很好,现在我们有一个表,以及一个可用于表示该表记录的对象。现在我们可以添加一个FruitTable
类,它将充当Fruit
和数据库本身之间的媒介。
class FruitTable {
private $columns = ['id', 'name', 'color', 'weight', 'order'];
private $table = 'fridge.fruits';
private $conn;
public function __construct($connection) {
$this->conn = $connection
}
public function findOneById($id) {
/**
* Query the DB and hydrate a Fruit instance
*/
return $fruit;
}
}
现在想象一下,我们需要能够根据水果的颜色更改order
Fruit
字段(我知道,这是我们正在努力的一些非常奇怪的业务) 。没问题,我们可以向FruitTable
添加一个函数来进行更新。
public function updateOrderByColor($newOrder, $color) {
/* assume proper validation */
$query = $this->conn->prepare("UPDATE fruits SET order = :newOrder WHERE color = :color");
$query->bindParam(':newOrder', $newOrder);
$query->bindParam(':color', $color);
$query->execute();
}
这是一个非常简单的例子,但它表明,与简单的Database
类相比,可以获得多大的灵活性。如果需要添加列,或者条件发生更改,则代码中只有一个位置需要跳入并乱用。如果查询出现问题,那么只有一个地方可以查找该错误。
这个例子并不完美,FruitTable
可能不应该直接负责处理数据库连接。您可以查看Doctrine和Eloquent如何处理查询构建器,以及它们如何设法将每个类与其余类进行封装。
答案 1 :(得分:0)
你需要将你的功能更新为这样的东西。首先将构建列数组,并使用','进行内嵌。循环然后绑定你的变量,然后绑定你的$ catID。
R = 36
# if the P value is three or greater
if p >= 3:
# it causes the circle to subtract p3 from 36
R -= p
# but if P is not equal to three or more
else:
# then I want for the code to say I do not want it to subtract p from 36.
pass
a.circle(b * (R, -i * 36)) # attention, i is not defined