CakePHP 3:正确编写实体模型函数

问题描述 投票:0回答:3

我有一个博客模型,我怀疑我没有正确编写代码以充分利用 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变量吗?我应该采取另一种方法吗?

php model-view-controller cakephp
3个回答
4
投票

我是否误解了实体函数应该如何编码?

是的,你知道,因为...

我应该从实体查询数据库,而不是访问有时不存在的该对象的预期变量吗?我应该采取另一种方法吗?

...实体应该是哑数据对象。当您从那里获取数据时,您将添加业务逻辑。任何数据操作都应该发生在模型层或服务的某个位置。大多数时候,使用 CakePHP 的人将代码放入表对象中,这有点OK。我在模型层中为不同的事物创建额外的类,并为它们命名空间

App\Model\SomeModule
或直接在我的应用程序根目录中
App\SomeModule
并注入我需要的任何其他内容(请求、表格...)。

这段代码也绝对低效:

public function getCommentCount(){
    $count = 0;
    foreach ($this->comments as $comment){
        if ( $comment->isPublished() ) {
            $count += 1;
        }
    }
    return $count;
}
  • 假设所有评论均已加载
  • 需要获取所有评论才能获得准确的计数
  • 它会迭代
  • 所有评论来过滤已发布的评论
  • 它在实体内部完成
如果有500条评论怎么办?为什么不简单地对数据库进行计数查询并按发布状态过滤它们?但这仍然需要您对每条记录执行一次额外的查询。因此,对于计数来说,如果您使用

计数器缓存行为,则会更加高效和简单。

如果您

真的需要在获取数据后但在渲染数据之前操作数据,请使用map/reduce。如果您想坚持低效的方式,您可以重构 getCommentCount() 并使用 map/reduce 来代替。链接的文档甚至包含一个计算内容的示例。


0
投票
在索引函数中您设置了

$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')); }

请参阅

返回记录总数了解更多信息。


0
投票
你可以这样做:

$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();
    
© www.soinside.com 2019 - 2024. All rights reserved.