我有一个博客模型,我怀疑我没有正确编写代码以充分利用 CakePHP 的 MVC 结构。
以下是我的帖子控制器中的一些片段。
public function view() {
$posts = $this->Posts->find('all')->contain([
'Comments' => ['Users'],
'Users'
]);
$this->set(compact('posts'));
}
public function index() {
$post = $this->Posts->find('all')->contain([
'Users'
])->limit(20);
$this->set(compact('post'));
}
这是来自
index.ctp
模板的片段
foreach ( $posts as $post ) {
<div class="post">
<h1 class="title>
<?= h($post->title) ?>
<small><?php echo $post->getCommentCount(); ?> comments</small>
</h1>
<div class="body">
<?= h($post->body) ?>
</div>
</div>
}
在我的帖子实体中,我有以下功能
public function getCommentCount(){
$count = 0;
foreach ($this->comments as $comment){
if ( $comment->isPublished() ) {
$count += 1;
}
}
return $count;
}
我的问题是我需要从
getCommentCount
调用 index.ctp
函数,其中 $posts
对象没有 comment
子对象(函数使用的)。
我是否误解了实体函数应该如何编码?我应该从实体查询数据库,而不是访问有时不存在的该对象的expected变量吗?我应该采取另一种方法吗?
我是否误解了实体函数应该如何编码?
是的,你知道,因为...
我应该从实体查询数据库,而不是访问有时不存在的该对象的预期变量吗?我应该采取另一种方法吗?
...实体应该是哑数据对象。当您从那里获取数据时,您将添加业务逻辑。任何数据操作都应该发生在模型层或服务的某个位置。大多数时候,使用 CakePHP 的人将代码放入表对象中,这有点OK。我在模型层中为不同的事物创建额外的类,并为它们命名空间
App\Model\SomeModule
或直接在我的应用程序根目录中 App\SomeModule
并注入我需要的任何其他内容(请求、表格...)。
这段代码也绝对低效:
public function getCommentCount(){
$count = 0;
foreach ($this->comments as $comment){
if ( $comment->isPublished() ) {
$count += 1;
}
}
return $count;
}
计数器缓存行为,则会更加高效和简单。
如果您真的需要在获取数据后但在渲染数据之前操作数据,请使用map/reduce。如果您想坚持低效的方式,您可以重构 getCommentCount() 并使用 map/reduce 来代替。链接的文档甚至包含一个计算内容的示例。
$post
,但在
index.ctp
中您使用了
$posts
,并且您错过了在查询中包含
Comments
关系。我给你改了:
public function index() {
$posts = $this->Posts->find('all')->contain([
'Users',
'Comments'
])
->limit(20);
$this->set(compact('posts'));
}
根据您的评论,您可以在这样的查询中获得总评论:
public function index() {
$posts = $this->Posts->find();
$posts->select([
'total_comments' => $posts->func()->sum('Comments.id')
])
->select($this->Posts)
->contain([
'Users',
'Comments'
])
->limit(20);
$this->set(compact('posts'));
}
请参阅
返回记录总数了解更多信息。
$posts = $this->Posts->find('all' , [
'fields' => array_merge(
$this->Posts->schema()->columns(), [
'countCommentsAlias' => '(
SELECT COUNT(comments.id)
FROM comments
WHERE comments.post_id = Posts.id
)',
'Users.name',
'Users.email'
]
),
'contain' => ['Users']
])
->toArray();