我最近了解到,在Codeigniter中,从查询中获取结果时,使用result()
或row()
可以添加字符串参数以将结果转换为自定义对象。
所以,我有这两个表:
Books
id
title
author_id
Authors
id
name
这个查询:
$this->db->select('b.id, b.title, a.name AS author_name');
$this->db->from('books AS b');
$this->db->join('authors AS a', 'b.author_id = a.id');
$query = $this->db->get();
$books = $query->result('Book');
$books
现在是一个Book对象数组(我加载了Book class
),所以我可以这样做:
foreach($books as $book) {
echo $book->title;
echo $book->author_name;
}
当然,author_name
是$book
的字段。对于这个非常简单的情况很好,但想象一个更复杂的情况,有更多的表,更多的类,涉及更多的字段,如果我可以直接在查询中创建一个$author
对象,有一些东西会很好像这样:
foreach($books as $book) {
echo $book->author->name;
}
我发现的一个解决方案是在Book类中有这样的东西:
class Book {
public function author()
{
if (empty($this->author)) {
$ci =& get_instance();
$this->author = $ci->db->get_where('authors',
['id' => $this->author_id])->row(0, 'Author');
}
return $this->author;
}
}
哪个有效,但这意味着在使用连接的原始查询之后,我将执行其他n个查询来获取作者。有更好的方法吗?
答案 0 :(得分:0)
对于任何给定的书籍,您将始终必须执行多个请求以获取不同的对象。您可以通过单个查询获得基本的,必要的信息。
在一个更复杂的情况下,例如作者,你可以在你的书中有一个字段“authorId”和“authorName”,以及一个“getAuthor”方法。
然后,您的SQL查询可以使用单个查询填充书籍对象中的作者姓名和ID,如果需要,该书可以加载复杂的作者对象。
答案 1 :(得分:0)
您的解决方案是一种不好的做法,因为您在实体中混合了大量代码。另一方面,没有任何自动方法在另一个内创建对象。要“自动”执行此操作,您必须使用ORM这样的Doctrine。
另一方面,在您的示例中,您应该将逻辑代码从Book移到模型类(SRP)到separate the concerns。
一个例子可能是:
public function getBook($id)
{
$book = $this->db->get_where('books', ['id' => $id])->row(0, 'Book');
$boo->author = $this->db->get_where('authors', ['id' => $book->author_id])->row(0, 'Author');
}
或者,您可以使用Closure封装所有内容并推迟实例化:
public function getBook($id)
{
$book = $this->db->get_where('books', ['id' => $id])->row(0, 'Book');
$book->authorClosure = $this->getAuthorClosure();
}
public function getAuthorClosure(Book $book)
{
$db = $this->db;
return function() use ($book , $db) {
return $db->get_where('authors', ['id' => $book->author_id])->row(0, 'Author');
};
}
public function getAuthor()
{
if (!isset($this->author))
{
$closure = $this->authorClosure;
$this->author = $closure();
}
return $this->author;
}
但是使用闭包,你应该有一个方法来返回作者而不是公共变量。