VSVverkeerskunde/gvq-api

View on GitHub
src/Statistics/Repositories/EmployeeParticipationDoctrineRepository.php

Summary

Maintainability
B
5 hrs
Test Coverage
<?php declare(strict_types=1);

namespace VSV\GVQ_API\Statistics\Repositories;

use function array_map;
use function array_sum;
use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\NonUniqueResultException;
use Doctrine\ORM\Query\Expr\Join;
use Ramsey\Uuid\UuidInterface;
use VSV\GVQ_API\Common\Repositories\AbstractDoctrineRepository;
use VSV\GVQ_API\Common\ValueObjects\Language;
use VSV\GVQ_API\Statistics\Models\EmployeeParticipation;
use VSV\GVQ_API\Statistics\Repositories\Entities\DetailedTopScoreEntity;
use VSV\GVQ_API\Statistics\Repositories\Entities\EmployeeParticipationEntity;
use VSV\GVQ_API\Statistics\ValueObjects\NaturalNumber;
use VSV\GVQ_API\User\ValueObjects\Email;

class EmployeeParticipationDoctrineRepository extends AbstractDoctrineRepository implements
    EmployeeParticipationRepository
{
    /**
     * @inheritdoc
     */
    protected function getRepositoryName(): string
    {
        return EmployeeParticipationEntity::class;
    }

    /**
     * @inheritdoc
     */
    public function save(EmployeeParticipation $employeeParticipation): void
    {
        /** @var EmployeeParticipationEntity $employeeParticipationEntity */
        $employeeParticipationEntity = $this->objectRepository->findOneBy(
            [
                'email' => $employeeParticipation->getEmail()->toNative(),
                'companyId' => $employeeParticipation->getCompanyId()->toString(),
            ]
        );

        if ($employeeParticipationEntity) {
            return;
        }

        $this->entityManager->persist(EmployeeParticipationEntity::fromEmployeeParticipation($employeeParticipation));
        $this->entityManager->flush();
    }

    /**
     * @inheritdoc
     * @throws NonUniqueResultException
     */
    public function countByCompany(UuidInterface $companyId): NaturalNumber
    {
        $qb = $this->entityManager->createQueryBuilder();

        $qb->select('count(participation.email)')
            ->from($this->getRepositoryName(), 'participation')
            ->where('participation.companyId = :companyId')
            ->setParameter(':companyId', $companyId->toString());

        $result = intval($qb->getQuery()->getSingleScalarResult());
        return new NaturalNumber($result);
    }

    public function countByCompanyAndLanguage(
        UuidInterface $companyId,
        Language $language
    ): int {
        $qb = $this->entityManager->createQueryBuilder();

        // select count(distinct t.email) from detailed_top_score t inner join employee_participation e ON (t.email=e.email) where e.company_id='01eb0ee6-ee25-4bb5-8b4e-a6b7213b548a' and t.language=‘nl'
        $qb->select('count(distinct participation.email)')
            ->from($this->getRepositoryName(), 'participation')
            ->innerJoin(DetailedTopScoreEntity::class, 'score', Join::WITH, 'score.email = participation.email AND score.language = :language')
            ->where($qb->expr()->eq('participation.companyId', ':companyId'))
            ->setParameter('companyId', $companyId->toString())
            ->setParameter('language', $language->toNative());

        $result = $qb->getQuery()->getSingleScalarResult();
        return (int) $result;
    }

    public function countPassedByCompany(
        UuidInterface $companyId
    ): int {
        $qb = $this->entityManager->createQueryBuilder();

        $qb->select('count(distinct participation.email)')
            ->from($this->getRepositoryName(), 'participation')
            ->innerJoin(DetailedTopScoreEntity::class, 'score', Join::WITH, 'score.email = participation.email AND score.score >= 7')
            ->where($qb->expr()->eq('participation.companyId', ':companyId'))
            ->setParameter('companyId', $companyId->toString());

        $result = $qb->getQuery()->getSingleScalarResult();
        return (int) $result;
    }

    public function countPassedByCompanyAndLanguage(
        UuidInterface $companyId,
        Language $language
    ): int {
        $qb = $this->entityManager->createQueryBuilder();

        $qb->select('count(distinct participation.email)')
            ->from($this->getRepositoryName(), 'participation')
            ->innerJoin(DetailedTopScoreEntity::class, 'score', Join::WITH, 'score.email = participation.email AND score.language = :language AND score.score >= 7')
            ->where($qb->expr()->eq('participation.companyId', ':companyId'))
            ->setParameter('companyId', $companyId->toString())
            ->setParameter('language', $language->toNative());

        $result = $qb->getQuery()->getSingleScalarResult();
        return (int) $result;
    }

    public function getByEmail(Email $email): iterable
    {
        $participations = $this->objectRepository->findBy(
            [
                'email' => $email->toNative(),
            ]
        );

        foreach ($participations as $participation) {
            yield $participation->toEmployeeParticipation();
        }
    }

    public function getAverageTopScoreForCompanyAndLanguage(
        UuidInterface $companyId,
        Language $language
    ): float {
        $qb = $this->entityManager->createQueryBuilder();

        $qb->select('max(score.score) maxScore')
            ->from($this->getRepositoryName(), 'participation')
            ->where('participation.companyId = :companyId')
            ->innerJoin(DetailedTopScoreEntity::class, 'score', Join::WITH, 'participation.email = score.email AND score.language = :language')
            ->groupBy('participation.email')
            ->setParameter('companyId', $companyId->toString())
            ->setParameter('language', $language->toNative());

        $result = $qb->getQuery()->getResult(AbstractQuery::HYDRATE_SCALAR);

        $numbers = array_map(
            function ($result) {
                return floatval($result['maxScore']);
            },
            $result
        );

        $avg = 0;
        if (!empty($numbers)) {
            $avg = array_sum($numbers)/count($numbers);
        }

        return $avg;
    }
}