HEX
Server: LiteSpeed
System: Linux houston.panomity.com 6.8.0-100-generic #100-Ubuntu SMP PREEMPT_DYNAMIC Tue Jan 13 16:40:06 UTC 2026 x86_64
User: nudepix (1011)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: //home/timetracker.panomity.com/tm.old/Repository/TaskRepository.php
<?php

/*
 * This file is part of the TaskManagementBundle for Kimai 2.
 * All rights reserved by Kevin Papst (www.kevinpapst.de).
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace KimaiPlugin\TaskManagementBundle\Repository;

use App\Entity\Team;
use App\Entity\Timesheet;
use App\Entity\User;
use App\Repository\Paginator\LoaderPaginator;
use App\Repository\Paginator\PaginatorInterface;
use DateTime;
use DateTimeZone;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\QueryBuilder;
use KimaiPlugin\TaskManagementBundle\Entity\Task;
use KimaiPlugin\TaskManagementBundle\Entity\TaskComment;
use KimaiPlugin\TaskManagementBundle\Repository\Loader\TaskLoader;
use KimaiPlugin\TaskManagementBundle\Repository\Query\TaskQuery;
use Pagerfanta\Pagerfanta;

/**
 * @extends \Doctrine\ORM\EntityRepository<Task>
 */
final class TaskRepository extends EntityRepository
{
    public function getUserTasksQuery(User $user, int $pageSize = 10, int $page = 1): TaskQuery
    {
        $query = new TaskQuery();
        $query->setUser($user);
        $query->setPageSize($pageSize);
        $query->setPage($page);
        $query->setStatus([Task::STATUS_PENDING, Task::STATUS_IN_PROGRESS]);
        $query->setBegin(new DateTime('now', new DateTimeZone($user->getTimezone())));

        return $query;
    }

    public function getPendingTasksQuery(User $user, int $pageSize = 10, int $page = 1): TaskQuery
    {
        $query = new TaskQuery();
        $query->setCurrentUser($user);
        $query->setUnassigned(true);
        $query->setPageSize($pageSize);
        $query->setPage($page);
        $query->setBegin(new DateTime('now', new DateTimeZone($user->getTimezone())));

        return $query;
    }

    public function findByTimesheet(Timesheet $timesheet): ?Task
    {
        $qb = $this->getEntityManager()->createQueryBuilder();

        $qb
            ->select('t')
            ->from(Task::class, 't')
            ->where($qb->expr()->isMemberOf(':timesheet', 't.timesheets'))
            ->setParameter('timesheet', [$timesheet])
        ;

        return $qb->getQuery()->getOneOrNullResult();
    }

    public function saveTask(Task $task): void
    {
        $entityManager = $this->getEntityManager();
        $entityManager->persist($task);
        $entityManager->flush();
    }

    public function deleteTask(Task $task): void
    {
        $entityManager = $this->getEntityManager();
        $entityManager->remove($task);
        $entityManager->flush();
    }

    public function getPagerfantaForQuery(TaskQuery $query): Pagerfanta
    {
        $paginator = new Pagerfanta($this->getPaginatorForQuery($query));
        $paginator->setMaxPerPage($query->getPageSize());
        $paginator->setCurrentPage($query->getPage());

        return $paginator;
    }

    private function getPaginatorForQuery(TaskQuery $query): PaginatorInterface
    {
        $qb = $this->getQueryBuilderForQuery($query);
        $qb1 = clone $qb;

        $qb
            ->resetDQLPart('select')
            ->resetDQLPart('orderBy')
            ->resetDQLPart('groupBy')
            ->select($qb->expr()->countDistinct('t.id'))
        ;
        $counter = (int) $qb->getQuery()->getSingleScalarResult();

        return new LoaderPaginator(new TaskLoader($qb1->getEntityManager()), $qb1, $counter);
    }

    /**
     * @param TaskQuery $query
     * @return Task[]
     */
    public function getTasksForQuery(TaskQuery $query): iterable
    {
        // this is using the paginator internally, as it will load all joined entities into the working unit
        // do not "optimize" to use the query directly, as it would results in hundreds of additional lazy queries
        $paginator = $this->getPaginatorForQuery($query);

        return $paginator->getAll();
    }

    private function getQueryBuilderForQuery(TaskQuery $query): QueryBuilder
    {
        if ($query->isUnassigned()) {
            return $this->getQueryBuilderForPendingTasks($query);
        }

        return $this->getQueryBuilderForCollection($query);
    }

    private function getQueryBuilderForPendingTasks(TaskQuery $query): QueryBuilder
    {
        $qb = $this->getEntityManager()->createQueryBuilder();

        $qb
            ->select('t')
            ->from(Task::class, 't')
            ->leftJoin('t.project', 'p')
            ->leftJoin('p.customer', 'c')
        ;

        $currentUser = $query->getCurrentUser();

        $unassigned = $qb->expr()->andX($qb->expr()->isNull('t.user'));

        if (null === $currentUser) {
            $unassigned->add($qb->expr()->isNull('t.team'));
        } elseif (!$currentUser->canSeeAllData()) {
            if ($currentUser->hasTeamAssignment()) {
                $unassigned->add(
                    $qb->expr()->orX(
                        $qb->expr()->isNull('t.team'),
                        $qb->expr()->in('t.team', ':userTeams')
                    )
                );
                $qb->setParameter('userTeams', $currentUser->getTeams());
            } else {
                $unassigned->add($qb->expr()->isNull('t.team'));
            }
        }

        $qb->andWhere($unassigned);

        // select "in progress" as well, because unassigned tasks can be started as well
        $qb->andWhere(
            $qb->expr()->in('t.status', [Task::STATUS_PENDING, Task::STATUS_IN_PROGRESS])
        );

        $qb->setMaxResults($query->getPageSize());

        $orderBy = 'endSort';
        if ($query->getOrder() === TaskQuery::ORDER_ASC) {
            $qb->addSelect('COALESCE(t.end, \'9999-12-31 23:59:59\') AS HIDDEN endSort');
        } else {
            $qb->addSelect('COALESCE(t.end, \'0000-12-31 23:59:59\') AS HIDDEN endSort');
        }

        $qb->addOrderBy($orderBy, $query->getOrder());

        return $qb;
    }

    private function getQueryBuilderForCollection(TaskQuery $query): QueryBuilder
    {
        $qb = $this->getEntityManager()->createQueryBuilder();

        $qb
            ->select('t')
            ->from(Task::class, 't')
            ->leftJoin('t.project', 'p')
            ->leftJoin('p.customer', 'c')
        ;

        $currentUser = $query->getCurrentUser();

        $user = [];

        if (null !== $query->getUser()) {
            $user[] = $query->getUser();
        }

        $user = array_merge($user, $query->getUsers());

        $permission = $qb->expr()->orX();

        if (null !== $currentUser && !$currentUser->canSeeAllData()) {
            // make sure that the user is in the list of users, if he is part of a team.
            // if teams are used and the user is not a teamlead, the list of users would be
            // empty and then leading to NOT limit the select by user IDs
            if (\count($user) === 0) {
                $user[] = $currentUser;

                /** @var Team $team */
                foreach ($currentUser->getTeams() as $team) {
                    if ($currentUser->isTeamleadOf($team)) {
                        foreach ($team->getUsers() as $tmpUser) {
                            $user[] = $tmpUser;
                        }
                    }
                }
            }

            // see tasks of team member in listing page
            if ($query->isWithTeamTasks() && $currentUser->hasTeamAssignment()) {
                $permission->add($qb->expr()->in('t.team', ':userTeams'));
                $qb->setParameter('userTeams', $currentUser->getTeams());
            }

            if ($query->isWithUnassigned()) {
                $orTeams = $qb->expr()->orX();
                if ($currentUser->hasTeamAssignment()) {
                    $orTeams->add($qb->expr()->isNull('t.team'));
                    $orTeams->add($qb->expr()->in('t.team', ':userTeams'));
                    $qb->setParameter('userTeams', $currentUser->getTeams());
                }
                if ($orTeams->count() > 0) {
                    $permission->add(
                        $qb->expr()->andX(
                            $qb->expr()->isNull('t.user'),
                            $orTeams
                        )
                    );
                }

                $permission->add(
                    $qb->expr()->andX(
                        $qb->expr()->isNull('t.user'),
                        $qb->expr()->isNull('t.team')
                    )
                );
            }
        }

        if (\count($user) > 0) {
            $user = array_map(function (User $user) {
                return $user->getId();
            }, $user);
            $user = array_unique($user);

            $permission->add($qb->expr()->in('t.user', $user));
        }

        if ($permission->count() > 0) {
            $qb->andWhere($permission);
        }

        if (null !== $query->getEnd()) {
            $orEnd = $qb->expr()->orX(
                $qb->expr()->lte('t.end', ':end'),
                $qb->expr()->isNull('t.end')
            );
            $qb->andWhere($orEnd)->setParameter('end', $query->getEnd());
        }

        if (!empty($query->getStatus())) {
            $qb->andWhere(
                $qb->expr()->in('t.status', $query->getStatus())
            );
        }

        if ($query->hasActivities()) {
            $qb->andWhere($qb->expr()->in('t.activity', ':activity'))
                ->setParameter('activity', $query->getActivities());
        }

        if (!empty($query->getTeams())) {
            $qb->andWhere($qb->expr()->in('t.team', ':team'))
                ->setParameter('team', $query->getTeams());
        }

        if ($query->hasProjects()) {
            $qb->andWhere($qb->expr()->in('t.project', ':project'))
                ->setParameter('project', $query->getProjects());
        } elseif ($query->hasCustomers()) {
            $qb->andWhere($qb->expr()->in('p.customer', ':customer'))
                ->setParameter('customer', $query->getCustomers());
        }

        $tags = $query->getTags();
        if (!empty($tags)) {
            $qb->andWhere($qb->expr()->isMemberOf(':tags', 't.tags'))
                ->setParameter('tags', $query->getTags());
        }

        $orderBy = $query->getOrderBy();

        switch ($orderBy) {
            case 'project':
                $orderBy = 'p.name';
                break;
            case 'customer':
                $orderBy = 'c.name';
                break;
            case 'activity':
                $qb->leftJoin('t.activity', 'a');
                $orderBy = 'a.name';
                break;
            case 'user':
                $qb->leftJoin('t.user', 'u');
                $orderBy = 'u.username';
                break;
            case 'team':
                $qb->leftJoin('t.team', 'team');
                $orderBy = 'team.name';
                break;
            case 'end':
                $orderBy = 'endSort';
                if ($query->getOrder() === TaskQuery::ORDER_ASC) {
                    $qb->addSelect('COALESCE(t.end, \'9999-12-31 23:59:59\') AS HIDDEN endSort');
                } else {
                    $qb->addSelect('COALESCE(t.end, \'0000-12-31 23:59:59\') AS HIDDEN endSort');
                }
                break;
            default:
                $orderBy = 't.' . $orderBy;
                break;
        }

        $qb->addOrderBy($orderBy, $query->getOrder());

        if ($query->hasSearchTerm()) {
            $searchAnd = $qb->expr()->andX();
            $searchTerm = $query->getSearchTerm();

            if ($searchTerm->hasSearchTerm()) {
                $searchAnd->add(
                    $qb->expr()->orX(
                        $qb->expr()->like('t.title', ':searchTerm'),
                        $qb->expr()->like('t.description', ':searchTerm')
                    )
                );
                $qb->setParameter('searchTerm', '%' . $searchTerm->getSearchTerm() . '%');
            }

            if ($searchAnd->count() > 0) {
                $qb->andWhere($searchAnd);
            }
        }

        $qb->setMaxResults($query->getPageSize());

        return $qb;
    }

    public function getComments(Task $task): array
    {
        $qb = $this->getEntityManager()->createQueryBuilder();
        $qb
            ->select('comments')
            ->from(TaskComment::class, 'comments')
            ->andWhere($qb->expr()->eq('comments.task', ':task'))
            ->addOrderBy('comments.pinned', 'DESC')
            ->addOrderBy('comments.createdAt', 'DESC')
            ->setParameter('task', $task)
        ;

        return $qb->getQuery()->getResult();
    }

    public function saveComment(TaskComment $comment): void
    {
        $entityManager = $this->getEntityManager();
        $entityManager->persist($comment);
        $entityManager->flush();
    }

    public function deleteComment(TaskComment $comment): void
    {
        $entityManager = $this->getEntityManager();
        $entityManager->remove($comment);
        $entityManager->flush();
    }
}