1
votes

I have a specific object that I pass to twig for a loop.

categories -> post -> comments

I pass the "categories" object from the controller to the loop.

I can see using dump() that the entire relation tree is in there, and I need to get the amount of comments for each category in twig.

Is it possible to have something like

categories->getTotalCommentCount()

Is it possible to have that getter inside the Categories entity?

Thanks a lot in advance.

2
As you suggested, you can create a method in your categories entity - iterate over the posts and sum the comments for each post. Loop is simplest but obviously if you are doing this repeatedly it might be an expensive operation. If so, you could use Doctrine persist and update events to save a count as a property of the Categories object and persist that to the db. YMMVDarragh Enright

2 Answers

4
votes

As you suggested in your question you could indeed add a getTotalComments() method to your top-level Category object.

I am making some assumptions about your code here but one example implementation might iterate/map/reduce over the collection of child Post objects and count their child Comment objects to sum a total; e.g:

<?php

class Categories
{
    public function getTotalCommentCount()
    {        
        return array_reduce($this->posts->toArray(), function ($total, Post $post) {
            return $total + $post->comments->count();
        }, 0);
    }
}

Or you may prefer a loop:

public function getTotalCommentCount()
{        
    $commentCount = 0;

    foreach ($this->posts as $post) {
        $commentCount += $post->count();
    }

    return $commentCount;
}

I am assuming you are using Doctrine - which means that the association will be an ArrayCollection or PersistentCollection. Either way, both implement PHP's Countable interface, which allow them to be used with PHP built-in function count() (and its alias sizeof(). This also means that there is a count() method defined on this object.

This may be computationally expensive so you might decide to do one of several things, including storing the value after computing it:

<?php

class Categories
{
    private $commentCount = null;

    public function getTotalCommentCount()
    {        
        if (!$this->commentCount) {
            $this->commentCount = 0;
            foreach ($this->posts as $post) {
                $this->commentCount += $post->count();
            }
        }

        return $this->commentCount;
    }
}

Or you could use Doctrine to create a persistent $commentCount property and use Doctrine's PrePersist and PreUpdate lifecycle hooks to compute the value when the record is being persisted to the database.

Something like this:

<?php

/**
 * @ORM\HasLifecycleEvents()
 */
class Categories
{
    /**
     * @ORM\Column(name="comment_count", type="integer")
     */
    private $commentCount;

    public function getTotalCommentCount()
    {        
        return $this->commentCount;
    }

    /**
     * @ORM\PrePersist()
     * @ORM\PreUpdate()
     */
    public function calculateCommentCount()
    {
        // this method runs every time 
        // this object is persisted/flushed 
        // to the database

        $this->commentCount = 0;
        foreach ($this->posts as $post) {
            $this->commentCount += $post->count();
        }
    }
}

More information on that here:

https://symfony.com/doc/current/doctrine/lifecycle_callbacks.html

Hope this helps :)

1
votes

If you create relation between categories and comment class, use something like this

sizeof($category1->post->comments)