0

I have an array of student objects. Each student has subjects as an array collection. Each subject has a function getStatus() that is calculated based on different arguments etc, thus there is no real property for status in the subject entity.

How can I count the number of subjects that are completed, in progress, and pending and display it per student in a table?

I could retrieve my students in my controller like this:

$students = $em->getRepository(Student::class)->findAll();

and then perhaps with loops count it somehow, but I don't get how.

I thought of creating a function that implements the filter on the array collection like seen in this answer, but I don't understand how to use that to filter on getStatus().

I also thought to implement ->matching with a criteria like this:

public function getSubjectsByStatus(string $status): ?Collection
{
    $subjects = $this->subjects->matching(
        Criteria::create()->where(Criteria::expr()->eq($this->getStatus(), $status))
    );

    return $subjects ?? null;
}

and then do a count on the returned collection, but the first parameter of eq() should be a string and I don't have a status property in the subject entity that can be used as a string, and adding a property now is not a good idea.

How can I count all subjects, pending subjects, completed subjects, and in progess subjects the best way?

Mentos93
  • 581
  • 1
  • 7
  • 28

1 Answers1

0

You probably should consider making your status value an actual field in your database, since your problem would be easy to solve with a SQL/DQL query.

Without that being the case, here is how you could implement your getSubjectsByStatus method:

public function getSubjectsByStatus(string $status): ?Collection
{
    return $this->tl1Configs->filter(function ($element) use ($status) {
        return $element->getStatus() == $status;
    });
}

But if you call that method three times to just count the amount of all status values, you are looping over your collection three times as well.

A "better" solution would probably be to make a specialized method to explicitly get these counts. This is just one way of achieving what you want though. A method to return an array of sub-collections instead of just status counts could is another solution if you want to actual work with the sub-collections (all depends on your actual usecase).

public function getSubjectStatusCounts(): array
{
    $statusCounts = [];
    foreach ($this->tl1Configs as $subject) {
        $statusCounts[$subject->getStatus()] = ($statusCounts[$subject->getStatus()] ?? 0) + 1;
    }

    return $statusCounts;
}
Tobias Xy
  • 2,039
  • 18
  • 19