带有连接表的 PDO FETCH_CLASS
Posted
技术标签:
【中文标题】带有连接表的 PDO FETCH_CLASS【英文标题】:PDO FETCH_CLASS with joined tables 【发布时间】:2013-02-18 14:50:14 【问题描述】:假设我有 2 个 php 对象:
<?php
class Post
public $id;
public $text;
public $user_id;
?>
和
<?php
class User
public $id
public $name
?>
每个帖子都有一个唯一的约束,数据库中有 1 个用户。
我想使用适用于所有“Post”属性的 PDO“FETCH_CLASS”方法将数据填充到“Post”对象中,但如何填充“User”中的属性?
我的 SQL 语句如下所示:
SELECT post.id,
post.text,
post.user_id,
user.id,
user.name
FROM POST INNER JOIN User on post.user_id = user.id
谢谢!
更新:
ATM 我这样填写我的“邮政”类:
$statement = $db -> prepare($query);
$statement -> execute();
$statement -> setFetchMode(PDO::FETCH_CLASS, 'Post');
$posts = $statement -> fetchAll();
那么我该如何更改它以填充另一个类“用户”?
解决方案:
$statement = $db -> prepare($query);
$statement -> execute();
$posts = array();
while (($row = $statement->fetch(PDO::FETCH_ASSOC)) !== false)
$post = new Post();
$post->id = $row['post_id'];
$post->text = $row['post_text'];
$post->created = $row['post_created'];
$post->image = $row['post_image'];
$post->url = $row['post_url'];
$post->weight = $row['post_weight'];
$post->likes = $row['post_likes'];
$user = new User();
$user->id = $row['user_id'];
$user->nickname = $row['user_nickname'];
$user->created= $row['user_created'];
$user->locked = $row['user_locked'];
$post->user = $user;
$posts[] = $post;
return $posts;
【问题讨论】:
您的问题帮助很大!谢谢! 【参考方案1】:你可以试试像这样使用__set方法:
<?php
include 'connection.php';
class Post
public $id;
public $text;
public $user;
public function __construct()
$this->user = new User();
public function __set($name, $value)
if (array_key_exists($name, get_object_vars($this->user)))
$this->user->$name = $value;
else
$this->$name = $value;
class User
public $id;
public $name;
$statement = $pdo->prepare("SELECT * FROM post "
. "LEFT JOIN user "
. "ON post.user_id = post.id");
$statement->execute();
$result = $statement->fetchAll(\PDO::FETCH_CLASS | \PDO::FETCH_PROPS_LATE, Post::class);
echo "<pre>";
var_dump($result);
【讨论】:
这不是说Post::$id
永远是null
吗?
这是一个有趣的解决方案,但不是最有效的方法。你可以做if (isset($this->$name)) $this->$name = $value; else $this->user->$name = $value
。 (我认为还有更短的方法......)【参考方案2】:
据我所知,不支持直接在 PDO 中。通常,如果您需要从查询结果创建复杂的对象图,那是 ORM 的职责。
如果您需要此功能,我建议您使用Doctrine 或Propel,而不是自己编写一些东西。还有其他可能更轻的重量,但我没有使用它们的经验。
编辑:
我想也许我误解了这个问题,因为我相信其他人可能会。我认为真正的问题是如何访问连接的列,而不是如何从它们创建对象。
在这种情况下,只需使用标准的 arry fethc 方法,如 PDO::FETCH_ASSOC
、PDO::FETCH_NUMERIC
或 PDO::FETCH_BOTH
,即可提供您查询的所有列。
所以如果你想把它变成一个“对象图”,你必须手动而不是使用PDO::FETCH_CLASS
。
例如:
//$db is pdo:
// also notice im aliase the columns prefixing the name so that we can tell what belongs to
// post and what belongs to user, an alternative approach would be to use FETCH_NUMERIC,
// which just uses the column positions from the seelct statement as the keys
// so in this case post.id would be in the array as key 0, and user.name would be in the
// array as key 4
$stmt = $db->prepare('SELECT post.id as p_id,
post.text as p_text,
post.user_id as p_user_id,
user.id as u_id,
user.name as u_name
FROM POST INNER JOIN User on post.user_id = user.id');
$stmt->execute();
while (($row = $stmt->fetch(PDO::FETCH_ASSOC)) !== false)
print_r($row);
/* will output:
Array (
'p_id' => 'value'
'p_text' => 'value'
'p_user_id' => 'value'
'u_id' => 'value',
'u_name' => 'value'
)
So now you need to decide how to create your objects with the information returned
*/
【讨论】:
谢谢。 ATM 如果这太“复杂”,我想我应该远离 PDO。没有简单的连接,哪些应用程序甚至存在? 我不明白它有什么复杂之处,尤其是考虑到唯一的其他选项是mysqli
,它更难使用且更冗长。都不支持从连接的查询结果中“水合”复杂的关系。
我不确定我是否正确理解了您的评论。你同意 PDO 应该支持吗?不使用 FETCH_CLASS 时是否支持?我现在会调查一下...
如果您使用FETCH_ASSOC
或FETCH_NUMERIC
,它将为您提供查询中的所有列...我以为您是在专门询问如何从 JOINED 查询结果创建多个对象。
我不是故意不清楚,但我理解它不足以更具体;)我只尝试阅读我的“JOINED”查询并填充两个对象,你能帮我如何到达那里?【参考方案3】:
并不是对 OQ 的真正回应,而是因为它在 Google 上不断出现(是的,我知道它已经有一年多了)。您会发现跳过循环并分别查询每个表会快得多。
选择 post.id, post.text, post.user_id, FROM POST INNER JOIN 用户在 post.user_id = user.id $statement = $db -> 准备($query); $语句->执行(); $statement -> setFetchMode(PDO::FETCH_CLASS, 'Post'); $posts = $statement -> fetchAll(); 选择用户 ID, 用户名 FROM POST INNER JOIN 用户在 post.user_id = user.id $statement = $db -> 准备($query); $语句->执行(); $statement -> setFetchMode(PDO::FETCH_CLASS, 'User'); $users = $statement -> fetchAll();【讨论】:
【参考方案4】:如果您处理多个表,可能会使用 PDO::FETCH_NAMED。或者使用 PDO::ATTR_FETCH_TABLE_NAMES。
【讨论】:
【参考方案5】:我的解决方法:
function groupQueryJoinClasses(\PDOStatement $stmt, $joinInfo = [], $idProperty = 'id')
$result = [];
$records = $stmt->fetchAll();
if ( !empty($joinInfo) )
foreach ($records as $record)
if ( !isset($result[$record->$idProperty]) )
$result[$record->$idProperty] = $record;
foreach ($joinInfo as $target => $classInfo)
$vars = get_object_vars($record);
$class = new $classInfo['class']();
foreach ($vars as $key => $value)
$keyData = explode('.', $key);
if ( $keyData[0] == $classInfo['prefix'])
$class->$keyData[1] = $value;
unset($result[$record->$idProperty]->$key);
if ( !is_array( $result[$record->$idProperty]->$target) )
$result[$record->$idProperty]->$target = [];
$targetArray = &$result[$record->$idProperty]->$target;
$targetArray[] = $class;
else
$result = $records;
return $result;
function getModel($query, $data, $entryClass, $joinInfo, $idProperty = 'id')
$pdo = new PDO(...);
$stmt = $pdo->prepare($query);
$stmt->execute($data);
$stmt->setFetchMode(\PDO::FETCH_CLASS, $entryClass);
return groupQueryJoinClasses($stmt, $joinInfo , $idProperty);
// Sample request
$query =
'SELECT
u.id as "id",
p.id as "Post.id",
p.name as "Post.name"
FROM `user` u
LEFT JOIN `posts` p ON p.user_id = u.id
where id = :id'
;
$data = [ ':id' => 1 ];
$joinInfo = [
'posts' => [
'class' => Post::class,
'prefix'=> 'Post'
]
];
$flowRules = getModel($query, $data, User::class, $joinInfo);
也许对任何人都感兴趣,或者也许有人会在这种方法中看到问题
【讨论】:
以上是关于带有连接表的 PDO FETCH_CLASS的主要内容,如果未能解决你的问题,请参考以下文章
是否有相当于 PDO::FETCH_CLASS 的 INSERT 或 UPDATE?
PDO 连接:带有 SET NAMES / CHARACTER SET 的 UTF-8 声明?