added team permissions (#996)

This commit is contained in:
Kevin Papst
2019-08-16 01:22:33 +02:00
committed by GitHub
parent 9611646bc6
commit 561ec3b1e9
124 changed files with 4122 additions and 362 deletions

View File

@@ -11,6 +11,7 @@ namespace App\Repository;
use App\Entity\Activity;
use App\Entity\Timesheet;
use App\Entity\User;
use App\Model\ActivityStatistic;
use App\Repository\Loader\ActivityLoader;
use App\Repository\Paginator\LoaderPaginator;
@@ -81,6 +82,47 @@ class ActivityRepository extends EntityRepository
return $stats;
}
private function addPermissionCriteria(QueryBuilder $qb, ?User $user = null, array $teams = [])
{
// make sure that all queries without a user see all projects
if (null === $user && empty($teams)) {
return;
}
// make sure that admins see all activities
if (null !== $user && ($user->isSuperAdmin() || $user->isAdmin())) {
return;
}
if (null !== $user) {
$teams = array_merge($teams, $user->getTeams()->toArray());
}
$qb->leftJoin('p.teams', 'teams')
->leftJoin('c.teams', 'c_teams');
if (empty($teams)) {
$qb->andWhere($qb->expr()->isNull('c_teams'));
$qb->andWhere($qb->expr()->isNull('teams'));
return;
}
$orProject = $qb->expr()->orX(
$qb->expr()->isNull('teams'),
$qb->expr()->isMemberOf(':teams', 'p.teams')
);
$qb->andWhere($orProject);
$orCustomer = $qb->expr()->orX(
$qb->expr()->isNull('c_teams'),
$qb->expr()->isMemberOf(':teams', 'c.teams')
);
$qb->andWhere($orCustomer);
$qb->setParameter('teams', $teams);
}
/**
* @deprecated since 1.1
*/
@@ -181,16 +223,11 @@ class ActivityRepository extends EntityRepository
$qb
->select('a')
->from(Activity::class, 'a')
->leftJoin('a.project', 'p')
->leftJoin('p.customer', 'c')
->addOrderBy('a.' . $query->getOrderBy(), $query->getOrder())
;
if (!$query->isGlobalsOnly()) {
$qb
->leftJoin('a.project', 'p')
->leftJoin('p.customer', 'c')
;
}
$where = $qb->expr()->andX();
if (in_array($query->getVisibility(), [ActivityQuery::SHOW_VISIBLE, ActivityQuery::SHOW_HIDDEN])) {
@@ -239,6 +276,8 @@ class ActivityRepository extends EntityRepository
$qb->andWhere($where);
}
$this->addPermissionCriteria($qb, $query->getCurrentUser());
return $qb;
}

View File

@@ -13,6 +13,7 @@ use App\Entity\Activity;
use App\Entity\Customer;
use App\Entity\Project;
use App\Entity\Timesheet;
use App\Entity\User;
use App\Model\CustomerStatistic;
use App\Repository\Loader\CustomerLoader;
use App\Repository\Paginator\LoaderPaginator;
@@ -107,8 +108,41 @@ class CustomerRepository extends EntityRepository
return $stats;
}
private function addPermissionCriteria(QueryBuilder $qb, ?User $user = null, array $teams = [])
{
// make sure that all queries without a user see all customers
if (null === $user && empty($teams)) {
return;
}
// make sure that admins see all customers
if (null !== $user && ($user->isSuperAdmin() || $user->isAdmin())) {
return;
}
if (null !== $user) {
$teams = array_merge($teams, $user->getTeams()->toArray());
}
$qb->leftJoin('c.teams', 'teams');
if (empty($teams)) {
$qb->andWhere($qb->expr()->isNull('teams'));
return;
}
$or = $qb->expr()->orX(
$qb->expr()->isNull('teams'),
$qb->expr()->isMemberOf(':teams', 'c.teams')
);
$qb->andWhere($or);
$qb->setParameter('teams', $teams);
}
/**
* @deprecated since 1.1
* @deprecated since 1.1 - don't use this method, it ignores team permission checks
*/
public function builderForEntityType($customer)
{
@@ -145,6 +179,8 @@ class CustomerRepository extends EntityRepository
$qb->setParameter('ignored', $query->getCustomerToIgnore());
}
$this->addPermissionCriteria($qb, $query->getUser(), $query->getTeams());
return $qb;
}
@@ -152,7 +188,7 @@ class CustomerRepository extends EntityRepository
{
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->select('c', 'meta')
$qb->select('c')
->from(Customer::class, 'c')
->leftJoin('c.meta', 'meta')
->orderBy('c.' . $query->getOrderBy(), $query->getOrder());
@@ -165,6 +201,8 @@ class CustomerRepository extends EntityRepository
$qb->setParameter('visible', false, \PDO::PARAM_BOOL);
}
$this->addPermissionCriteria($qb, $query->getCurrentUser(), $query->getTeams());
return $qb;
}

View File

@@ -69,6 +69,27 @@ final class ActivityIdLoader implements LoaderInterface
->andWhere($qb->expr()->in('p.id', $projectIds))
->getQuery()
->execute();
$qb = $em->createQueryBuilder();
$qb->select('PARTIAL a.{id}', 'PARTIAL project.{id}', 'teams', 'teamlead')
->from(Activity::class, 'a')
->leftJoin('a.project', 'project')
->leftJoin('project.teams', 'teams')
->leftJoin('teams.teamlead', 'teamlead')
->andWhere($qb->expr()->in('a.id', $ids))
->getQuery()
->execute();
$qb = $em->createQueryBuilder();
$qb->select('PARTIAL a.{id}', 'PARTIAL project.{id}', 'PARTIAL customer.{id}', 'teams', 'teamlead')
->from(Activity::class, 'a')
->leftJoin('a.project', 'project')
->leftJoin('project.customer', 'customer')
->leftJoin('customer.teams', 'teams')
->leftJoin('teams.teamlead', 'teamlead')
->andWhere($qb->expr()->in('a.id', $ids))
->getQuery()
->execute();
}
}
}

View File

@@ -42,5 +42,14 @@ final class CustomerIdLoader implements LoaderInterface
->andWhere($qb->expr()->in('c.id', $ids))
->getQuery()
->execute();
$qb = $em->createQueryBuilder();
$qb->select('PARTIAL c.{id}', 'teams', 'teamlead')
->from(Customer::class, 'c')
->leftJoin('c.teams', 'teams')
->leftJoin('teams.teamlead', 'teamlead')
->andWhere($qb->expr()->in('c.id', $ids))
->getQuery()
->execute();
}
}

View File

@@ -50,5 +50,24 @@ final class ProjectIdLoader implements LoaderInterface
->andWhere($qb->expr()->in('p.id', $ids))
->getQuery()
->execute();
$qb = $em->createQueryBuilder();
$qb->select('PARTIAL p.{id}', 'teams', 'teamlead')
->from(Project::class, 'p')
->leftJoin('p.teams', 'teams')
->leftJoin('teams.teamlead', 'teamlead')
->andWhere($qb->expr()->in('p.id', $ids))
->getQuery()
->execute();
$qb = $em->createQueryBuilder();
$qb->select('PARTIAL p.{id}', 'PARTIAL customer.{id}', 'teams', 'teamlead')
->from(Project::class, 'p')
->leftJoin('p.customer', 'customer')
->leftJoin('customer.teams', 'teams')
->leftJoin('teams.teamlead', 'teamlead')
->andWhere($qb->expr()->in('p.id', $ids))
->getQuery()
->execute();
}
}

View File

@@ -0,0 +1,46 @@
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Repository\Loader;
use App\Entity\Team;
use Doctrine\ORM\EntityManagerInterface;
final class TeamIdLoader implements LoaderInterface
{
/**
* @var EntityManagerInterface
*/
private $entityManager;
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
/**
* @param int[] $ids
*/
public function loadResults(array $ids): void
{
if (empty($ids)) {
return;
}
$em = $this->entityManager;
$qb = $em->createQueryBuilder();
$qb->select('PARTIAL t.{id}', 'users')
->from(Team::class, 't')
->leftJoin('t.users', 'users')
->andWhere($qb->expr()->in('t.id', $ids))
->getQuery()
->execute();
}
}

View File

@@ -0,0 +1,38 @@
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Repository\Loader;
use App\Entity\Team;
use Doctrine\ORM\EntityManagerInterface;
final class TeamLoader implements LoaderInterface
{
/**
* @var TeamIdLoader
*/
private $loader;
public function __construct(EntityManagerInterface $entityManager)
{
$this->loader = new TeamIdLoader($entityManager);
}
/**
* @param Team[] $teams
*/
public function loadResults(array $teams): void
{
$ids = array_map(function (Team $team) {
return $team->getId();
}, $teams);
$this->loader->loadResults($ids);
}
}

View File

@@ -12,6 +12,7 @@ namespace App\Repository;
use App\Entity\Activity;
use App\Entity\Project;
use App\Entity\Timesheet;
use App\Entity\User;
use App\Model\ProjectStatistic;
use App\Repository\Loader\ProjectLoader;
use App\Repository\Paginator\LoaderPaginator;
@@ -91,8 +92,49 @@ class ProjectRepository extends EntityRepository
return $stats;
}
private function addPermissionCriteria(QueryBuilder $qb, ?User $user = null, array $teams = [])
{
// make sure that all queries without a user see all projects
if (null === $user && empty($teams)) {
return;
}
// make sure that admins see all projects
if (null !== $user && ($user->isSuperAdmin() || $user->isAdmin())) {
return;
}
if (null !== $user) {
$teams = array_merge($teams, $user->getTeams()->toArray());
}
$qb->leftJoin('p.teams', 'teams')
->leftJoin('c.teams', 'c_teams');
if (empty($teams)) {
$qb->andWhere($qb->expr()->isNull('c_teams'));
$qb->andWhere($qb->expr()->isNull('teams'));
return;
}
$orProject = $qb->expr()->orX(
$qb->expr()->isNull('teams'),
$qb->expr()->isMemberOf(':teams', 'p.teams')
);
$qb->andWhere($orProject);
$orCustomer = $qb->expr()->orX(
$qb->expr()->isNull('c_teams'),
$qb->expr()->isMemberOf(':teams', 'c.teams')
);
$qb->andWhere($orCustomer);
$qb->setParameter('teams', $teams);
}
/**
* @deprecated since 1.1
* @deprecated since 1.1 - don't use this method, it ignores team permission checks
*/
public function builderForEntityType($project, $customer)
{
@@ -114,7 +156,7 @@ class ProjectRepository extends EntityRepository
$qb = $this->getEntityManager()->createQueryBuilder();
$qb
->select('p', 'c')
->select('p')
->from(Project::class, 'p')
->leftJoin('p.customer', 'c')
->addOrderBy('c.name', 'ASC')
@@ -140,6 +182,8 @@ class ProjectRepository extends EntityRepository
$qb->setParameter('ignored', $query->getProjectToIgnore());
}
$this->addPermissionCriteria($qb, $query->getUser(), $query->getTeams());
return $qb;
}
@@ -150,11 +194,11 @@ class ProjectRepository extends EntityRepository
$qb
->select('p')
->from(Project::class, 'p')
->leftJoin('p.customer', 'c')
;
if (in_array($query->getVisibility(), [ProjectQuery::SHOW_VISIBLE, ProjectQuery::SHOW_HIDDEN])) {
$qb
->leftJoin('p.customer', 'c')
->andWhere($qb->expr()->eq('p.visible', ':visible'))
->andWhere($qb->expr()->eq('c.visible', ':customer_visible'))
;
@@ -173,6 +217,8 @@ class ProjectRepository extends EntityRepository
->setParameter('customer', $query->getCustomer());
}
$this->addPermissionCriteria($qb, $query->getCurrentUser());
$qb->orderBy('p.' . $query->getOrderBy(), $query->getOrder());
return $qb;

View File

@@ -9,6 +9,9 @@
namespace App\Repository\Query;
use App\Entity\Team;
use App\Entity\User;
/**
* Base class for advanced Repository queries.
*/
@@ -44,6 +47,45 @@ class BaseQuery
* @var string
*/
private $resultType = self::RESULT_TYPE_PAGER;
/**
* @var User
*/
private $user;
/**
* @var Team[]
*/
private $teams = [];
public function addTeam(Team $team): self
{
$this->teams[$team->getId()] = $team;
return $this;
}
/**
* @return Team[]
*/
public function getTeams(): array
{
return array_values($this->teams);
}
public function getCurrentUser(): ?User
{
return $this->user;
}
/**
* @param User $user
* @return $this
*/
public function setCurrentUser(User $user)
{
$this->user = $user;
return $this;
}
/**
* @return int

View File

@@ -10,6 +10,8 @@
namespace App\Repository\Query;
use App\Entity\Customer;
use App\Entity\Team;
use App\Entity\User;
/**
* Can be used for advanced queries with the: CustomerRepository
@@ -24,6 +26,14 @@ final class CustomerFormTypeQuery
* @var Customer|null
*/
private $customerToIgnore;
/**
* @var User
*/
private $user;
/**
* @var array<Team>
*/
private $teams = [];
/**
* @param Customer|int|null $customer
@@ -33,6 +43,33 @@ final class CustomerFormTypeQuery
$this->customer = $customer;
}
public function addTeam(Team $team): CustomerFormTypeQuery
{
$this->teams[$team->getId()] = $team;
return $this;
}
/**
* @return Team[]
*/
public function getTeams(): array
{
return array_values($this->teams);
}
public function getUser(): ?User
{
return $this->user;
}
public function setUser(User $user): CustomerFormTypeQuery
{
$this->user = $user;
return $this;
}
/**
* @return Customer|int|null
*/

View File

@@ -11,6 +11,8 @@ namespace App\Repository\Query;
use App\Entity\Customer;
use App\Entity\Project;
use App\Entity\Team;
use App\Entity\User;
final class ProjectFormTypeQuery
{
@@ -26,6 +28,14 @@ final class ProjectFormTypeQuery
* @var Project|null
*/
private $projectToIgnore;
/**
* @var User
*/
private $user;
/**
* @var array<Team>
*/
private $teams = [];
/**
* @param Project|int|null $project
@@ -37,6 +47,33 @@ final class ProjectFormTypeQuery
$this->customer = $customer;
}
public function addTeam(Team $team): ProjectFormTypeQuery
{
$this->teams[$team->getId()] = $team;
return $this;
}
/**
* @return Team[]
*/
public function getTeams(): array
{
return array_values($this->teams);
}
public function getUser(): ?User
{
return $this->user;
}
public function setUser(User $user): ProjectFormTypeQuery
{
$this->user = $user;
return $this;
}
/**
* @return Customer|int|null
*/

View File

@@ -11,4 +11,8 @@ namespace App\Repository\Query;
class TagQuery extends BaseQuery
{
public function __construct()
{
$this->setOrderBy('name');
}
}

View File

@@ -0,0 +1,18 @@
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Repository\Query;
class TeamQuery extends BaseQuery
{
public function __construct()
{
$this->setOrderBy('name');
}
}

View File

@@ -28,7 +28,7 @@ class TimesheetQuery extends ActivityQuery
/**
* @var User|null
*/
protected $user;
protected $timesheetUser;
/**
* @var Activity|null
*/
@@ -63,7 +63,7 @@ class TimesheetQuery extends ActivityQuery
*/
public function getUser()
{
return $this->user;
return $this->timesheetUser;
}
/**
@@ -72,7 +72,7 @@ class TimesheetQuery extends ActivityQuery
*/
public function setUser($user = null)
{
$this->user = $user;
$this->timesheetUser = $user;
return $this;
}
@@ -256,7 +256,7 @@ class TimesheetQuery extends ActivityQuery
return true;
}
if ($this->user !== null) {
if ($this->timesheetUser !== null) {
return true;
}

View File

@@ -0,0 +1,55 @@
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Repository\Query;
use App\Entity\Team;
use App\Entity\User;
/**
* Can be used for pre-filling form types with the: UserRepository
*/
final class UserFormTypeQuery
{
/**
* @var User
*/
private $user;
/**
* @var array<Team>
*/
private $teams = [];
public function addTeam(Team $team): UserFormTypeQuery
{
$this->teams[$team->getId()] = $team;
return $this;
}
/**
* @return Team[]
*/
public function getTeams(): array
{
return array_values($this->teams);
}
public function getUser(): ?User
{
return $this->user;
}
public function setUser(User $user): UserFormTypeQuery
{
$this->user = $user;
return $this;
}
}

View File

@@ -9,12 +9,26 @@
namespace App\Repository;
use App\Entity\Tag;
use App\Repository\Query\TagQuery;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\ORMException;
use Pagerfanta\Adapter\DoctrineORMAdapter;
use Pagerfanta\Pagerfanta;
class TagRepository extends EntityRepository
{
use RepositoryTrait;
/**
* @param Tag $tag
* @throws ORMException
* @throws \Doctrine\ORM\OptimisticLockException
*/
public function deleteTag(Tag $tag)
{
$entityManager = $this->getEntityManager();
$entityManager->remove($tag);
$entityManager->flush();
}
/**
* Find ids of the given tagNames separated by comma
@@ -68,7 +82,7 @@ class TagRepository extends EntityRepository
* - amount
*
* @param TagQuery $query
* @return array|\Doctrine\ORM\QueryBuilder|\Pagerfanta\Pagerfanta
* @return Pagerfanta
*/
public function getTagCount(TagQuery $query)
{
@@ -79,9 +93,12 @@ class TagRepository extends EntityRepository
->leftJoin('tag.timesheets', 'timesheets')
->addGroupBy('tag.id')
->addGroupBy('tag.name')
->orderBy('tag.name')
;
->orderBy('tag.' . $query->getOrderBy(), $query->getOrder());
return $this->getBaseQueryResult($qb, $query);
$paginator = new Pagerfanta(new DoctrineORMAdapter($qb->getQuery(), false));
$paginator->setMaxPerPage($query->getPageSize());
$paginator->setCurrentPage($query->getPage());
return $paginator;
}
}

View File

@@ -0,0 +1,99 @@
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Repository;
use App\Entity\Team;
use App\Entity\Timesheet;
use App\Repository\Loader\TeamLoader;
use App\Repository\Paginator\LoaderPaginator;
use App\Repository\Paginator\PaginatorInterface;
use App\Repository\Query\TeamQuery;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\ORMException;
use Doctrine\ORM\QueryBuilder;
use Pagerfanta\Pagerfanta;
class TeamRepository extends EntityRepository
{
/**
* @param Team $team
* @throws ORMException
* @throws \Doctrine\ORM\OptimisticLockException
*/
public function saveTeam(Team $team)
{
$entityManager = $this->getEntityManager();
$entityManager->persist($team);
$entityManager->flush();
}
/**
* @param Team $team
* @throws ORMException
* @throws \Doctrine\ORM\OptimisticLockException
*/
public function deleteTeam(Team $team)
{
$entityManager = $this->getEntityManager();
$entityManager->remove($team);
$entityManager->flush();
}
public function getPagerfantaForQuery(TeamQuery $query): Pagerfanta
{
$paginator = new Pagerfanta($this->getPaginatorForQuery($query));
$paginator->setMaxPerPage($query->getPageSize());
$paginator->setCurrentPage($query->getPage());
return $paginator;
}
protected function getPaginatorForQuery(TeamQuery $query): PaginatorInterface
{
$qb = $this->getQueryBuilderForQuery($query);
$qb
->resetDQLPart('select')
->resetDQLPart('orderBy')
->select($qb->expr()->countDistinct('t.id'))
;
$counter = (int) $qb->getQuery()->getSingleScalarResult();
$qb = $this->getQueryBuilderForQuery($query);
return new LoaderPaginator(new TeamLoader($qb->getEntityManager()), $qb, $counter);
}
/**
* @param TeamQuery $query
* @return Timesheet[]
*/
public function getTeamsForQuery(TeamQuery $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(TeamQuery $query): QueryBuilder
{
$qb = $this->getEntityManager()->createQueryBuilder();
$qb
->select('t')
->from(Team::class, 't')
;
$qb->orderBy('t.' . $query->getOrderBy(), $query->getOrder());
return $qb;
}
}

View File

@@ -456,6 +456,36 @@ class TimesheetRepository extends EntityRepository
return $counter;
}
private function addPermissionCriteria(QueryBuilder $qb, ?User $user = null, array $teams = [])
{
// make sure that all queries without a user see all projects
if (null === $user && empty($teams)) {
return;
}
if (empty($teams)) {
return;
}
// make sure that admins see all timesheet records
if (null !== $user && ($user->isSuperAdmin() || $user->isAdmin())) {
return;
}
$qb
->leftJoin('p.customer', 'c')
->leftJoin('p.teams', 'teams')
->leftJoin('c.teams', 'c_teams');
$orTeam = $qb->expr()->orX(
$qb->expr()->isMemberOf(':teams', 'p.teams'),
$qb->expr()->isMemberOf(':teams', 'c.teams')
);
$qb->andWhere($orTeam);
$qb->setParameter('teams', $teams);
}
public function getPagerfantaForQuery(TimesheetQuery $query): Pagerfanta
{
$paginator = new Pagerfanta($this->getPaginatorForQuery($query));
@@ -500,11 +530,43 @@ class TimesheetRepository extends EntityRepository
$qb
->select('t')
->from(Timesheet::class, 't')
->leftJoin('t.project', 'p')
;
$user = [];
if (null !== $query->getUser()) {
$qb->andWhere('t.user = :user')
->setParameter('user', $query->getUser());
$user[] = $query->getUser();
}
if (null === $query->getUser() && null !== $query->getCurrentUser()) {
$currentUser = $query->getCurrentUser();
if (!$currentUser->isSuperAdmin() && !$currentUser->isAdmin()) {
foreach ($currentUser->getTeams() as $team) {
if ($currentUser->isTeamleadOf($team)) {
$query->addTeam($team);
}
}
}
}
if (!empty($query->getTeams())) {
foreach ($query->getTeams() as $team) {
$user = array_merge($user, $team->getUsers()->toArray());
}
}
$user = array_map(function ($user) {
if ($user instanceof User) {
return $user->getId();
}
return $user;
}, $user);
$user = array_unique($user);
if (!empty($user)) {
$qb->andWhere($qb->expr()->in('t.user', $user));
}
if (null !== $query->getBegin()) {
@@ -539,7 +601,6 @@ class TimesheetRepository extends EntityRepository
$qb->andWhere('t.project = :project')
->setParameter('project', $query->getProject());
} elseif (null !== $query->getCustomer()) {
$qb->join('t.project', 'p');
$qb->andWhere('p.customer = :customer')
->setParameter('customer', $query->getCustomer());
}
@@ -551,6 +612,8 @@ class TimesheetRepository extends EntityRepository
->setParameter('tags', $query->getTags());
}
$this->addPermissionCriteria($qb, $query->getCurrentUser(), $query->getTeams());
$qb->orderBy('t.' . $query->getOrderBy(), $query->getOrder());
return $qb;

View File

@@ -10,8 +10,10 @@
namespace App\Repository;
use App\Entity\User;
use App\Repository\Query\UserFormTypeQuery;
use App\Repository\Query\UserQuery;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Security\User\UserLoaderInterface;
class UserRepository extends EntityRepository implements UserLoaderInterface
@@ -26,12 +28,28 @@ class UserRepository extends EntityRepository implements UserLoaderInterface
}
/**
* Used to fetch the currently logged-in user.
*
* @param int $id
* @return null|User
*/
public function getUserById($id): ?User
{
return $this->find($id);
try {
return $this->createQueryBuilder('u')
->select('u', 'p', 't', 'tu', 'tl')
->leftJoin('u.preferences', 'p')
->leftJoin('u.teams', 't')
->leftJoin('t.users', 'tu')
->leftJoin('t.teamlead', 'tl')
->where('u.id = :id')
->setParameter('id', $id)
->getQuery()
->getSingleResult();
} catch (\Exception $ex) {
}
return null;
}
/**
@@ -103,12 +121,49 @@ class UserRepository extends EntityRepository implements UserLoaderInterface
public function loadUserByUsername($username)
{
return $this->createQueryBuilder('u')
->select('u', 'p')
->select('u', 'p', 't', 'tu', 'tl')
->leftJoin('u.preferences', 'p')
->leftJoin('u.teams', 't')
->leftJoin('t.users', 'tu')
->leftJoin('t.teamlead', 'tl')
->where('u.username = :username')
->orWhere('u.email = :username')
->setParameter('username', $username)
->getQuery()
->getSingleResult();
}
public function getQueryBuilderForFormType(UserFormTypeQuery $query): QueryBuilder
{
$qb = $this->createQueryBuilder('u');
$qb->andWhere($qb->expr()->eq('u.enabled', ':enabled'));
$qb->setParameter('enabled', true, \PDO::PARAM_BOOL);
$qb->orderBy('u.username', 'ASC');
$this->addPermissionCriteria($qb, $query->getUser(), $query->getTeams());
return $qb;
}
private function addPermissionCriteria(QueryBuilder $qb, ?User $user = null, array $teams = [])
{
// make sure that all queries without a user see all user
if (null === $user && empty($teams)) {
return;
}
// make sure that admins see all user
if (null !== $user && ($user->isSuperAdmin() || $user->isAdmin())) {
return;
}
if (null !== $user) {
$qb->leftJoin('u.teams', 'teams')
->leftJoin('teams.users', 'users')
->andWhere('teams.teamlead = :id')
->setParameter('id', $user);
}
}
}