src/Contact/Repository/DoctrineContactRepository.php line 79

  1. <?php
  2. declare(strict_types=1);
  3. /**
  4.  * Copyright (c) 2019 TECLA Consulting Group oü.
  5.  * All rights reserved.
  6.  *
  7.  * This unpublished material is proprietary to TECLA Consulting Group oü.
  8.  * All rights reserved. The methods and
  9.  * techniques described herein are considered trade secrets
  10.  * and/or confidential. Reproduction or distribution, in whole
  11.  * or in part, is forbidden except by express written permission
  12.  * of TECLA Consulting Group oü.
  13.  *
  14.  * @author    Matúš Sýkorjak <matus@tecla.no>
  15.  * @copyright 2019 TECLA Consulting Group oü
  16.  */
  17. namespace App\Contact\Repository;
  18. use App\Contact\Doctrine\DBAL\Types\ContactIdType;
  19. use App\Contact\Doctrine\DBAL\Types\GenderType;
  20. use App\Contact\Doctrine\DBAL\Types\GroupIdType;
  21. use App\Contact\Doctrine\DBAL\Types\IndustrySectorType;
  22. use App\Contact\Doctrine\DBAL\Types\MaritalStatusType;
  23. use App\Contact\Doctrine\DBAL\Types\WorkOccupationType;
  24. use App\Contact\Model\Contact;
  25. use App\Contact\Model\ContactAddressInterface;
  26. use App\Contact\Model\ContactInterface;
  27. use App\Contact\Model\ContactPermissionInterface;
  28. use App\Contact\Model\ContactRelationshipCustomerSupplierInterface;
  29. use App\Contact\Model\GroupItemInterface;
  30. use App\Contact\Model\Identity\ContactIdInterface;
  31. use App\Contact\Model\Relationship\AccountantInterface;
  32. use App\Contact\Model\Relationship\AuthorizedAccountantInterface;
  33. use App\Contact\Model\Relationship\ManagingDirectorInterface;
  34. use App\Contact\Model\Relationship\EmploymentInterface;
  35. use App\Invoice\Model\InvoicePaymentNotificationInterface;
  36. use App\Note\Model\NoteInterface;
  37. use App\Note\Model\NotePermissionInterface;
  38. use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
  39. use Doctrine\ORM\Query\Expr\Join;
  40. use Doctrine\ORM\QueryBuilder;
  41. use Doctrine\Persistence\ManagerRegistry;
  42. class DoctrineContactRepository extends ServiceEntityRepository
  43. {
  44.     public function __construct(ManagerRegistry $registry)
  45.     {
  46.         parent::__construct($registryContact::class);
  47.     }
  48.     /**
  49.      * Returns contact with $authorizeId if contact with $id has permission to access it.
  50.      */
  51.     public function findOneAuthorizedById(ContactIdInterface $contactIdContactIdInterface $authorizedContactId): ?ContactInterface
  52.     {
  53.         $qb $this->createQueryBuilder('c');
  54.         return $qb
  55.             ->leftJoin(ContactPermissionInterface::class, 'cp'Join::WITH$qb->expr()->eq('cp.contact''c.id'))
  56.             ->andWhere('c.id = :authorizedId')
  57.             ->andWhere($qb->expr()->eq('cp.authorizedContact'':id'))
  58.             ->addGroupBy('c.id')
  59.             ->setParameter('id'$contactIdContactIdType::NAME)
  60.             ->setParameter('authorizedId'$authorizedContactIdContactIdType::NAME)
  61.             ->getQuery()
  62.             ->getOneOrNullResult();
  63.     }
  64.     /**
  65.      * Returns all contacts for what is contact with given ID authorized.
  66.      *
  67.      * @param ?int $limit
  68.      * @param ?int $offset
  69.      *
  70.      * @return ContactInterface[]|null
  71.      */
  72.     public function findAllAuthorized(ContactIdInterface $id, array $criteria null, array $orderBy null, ?int $limit null, ?int $offset null): ?array
  73.     {
  74.         return $this
  75.             ->createQueryBuilderAllAuthorized(false$id$criteria$orderBy$limit$offset)
  76.             ->getQuery()
  77.             ->getResult()
  78.         ;
  79.     }
  80.     /**
  81.      * Counts all contacts for what is contact with given ID authorized.
  82.      */
  83.     public function countAllAuthorized(ContactIdInterface $id, array $criteria null): int
  84.     {
  85.         return (int) ($this
  86.             ->createQueryBuilderAllAuthorized(true$id$criteria)
  87.             ->getQuery()
  88.             ->getSingleScalarResult())
  89.         ;
  90.     }
  91.     /**
  92.      * Returns Contact of person type with given unique information.
  93.      */
  94.     public function findOnePersonByUniqueInformation(string $email): ?ContactInterface
  95.     {
  96.         $qb $this->createQueryBuilder('c');
  97.         return $qb
  98.             ->where('c.type = :type')
  99.             ->andWhere('c.email = :email')
  100.             ->setParameter('type'ContactInterface::TYPE_PERSON)
  101.             ->setParameter('email'$email)
  102.             ->getQuery()
  103.             ->getOneOrNullResult();
  104.     }
  105.     /**
  106.      * Returns Contact of company type with given unique information.
  107.      */
  108.     public function findOneCompanyByUniqueInformation(string $registrationNumberstring $country): ?ContactInterface
  109.     {
  110.         $qb $this->createQueryBuilder('c');
  111.         return $qb
  112.             ->where('c.type = :type')
  113.             ->andWhere('c.registrationNumber = :registrationNumber')
  114.             ->andWhere('c.country = :country')
  115.             ->setParameter('type'ContactInterface::TYPE_COMPANY)
  116.             ->setParameter('registrationNumber'$registrationNumber)
  117.             ->setParameter('country'$country)
  118.             ->getQuery()
  119.             ->getOneOrNullResult();
  120.     }
  121.     public function createAddContactAwareQueryBuilder(ContactIdInterface $authorizedContactId): QueryBuilder
  122.     {
  123.         $qb $this->createQueryBuilder('c');
  124.         return $qb
  125.             ->innerJoin(ContactPermissionInterface::class, 'cp'Join::WITH$qb->expr()->eq('c.id''cp.contact'))
  126.             ->where($qb->expr()->eq('cp.authorizedContact'':id'))
  127.             ->setParameter('id'$authorizedContactIdContactIdType::NAME);
  128.     }
  129.     public function createAddContactAccessAccessorQueryBuilder(ContactIdInterface $authorizedContactId)
  130.     {
  131.         $qb $this->createQueryBuilder('c');
  132.         return $qb
  133.             ->innerJoin(ContactPermissionInterface::class, 'cp'Join::WITH$qb->expr()->eq('c.id''cp.contact'))
  134.             ->where($qb->expr()->eq('cp.authorizedContact'':id'))
  135.             ->andWhere($qb->expr()->eq('c.type'':personType'))
  136.             ->setParameter('id'$authorizedContactIdContactIdType::NAME)
  137.             ->setParameter('personType'ContactInterface::TYPE_PERSON);
  138.     }
  139.     /**
  140.      * Create query builder for all contacts for what is contact with given ID authorized.
  141.      *
  142.      * @param ?int $limit
  143.      * @param ?int $offset
  144.      */
  145.     private function createQueryBuilderAllAuthorized(bool $isCountContactIdInterface $id, array $criteria null, array $orderBy null, ?int $limit null, ?int $offset null): QueryBuilder
  146.     {
  147.         $addFullNameQuery false;
  148.         $addContactEmailQuery false;
  149.         $addGroupQuery false;
  150.         $addManagingDirectorQuery false;
  151.         $addAccountantQuery false;
  152.         $addAuthorizedAccountantQuery false;
  153.         $addEmploymentRelationshipQuery false;
  154.         $addRelationshipCustomerSupplierQuery false;
  155.         $addNotificationInvoicePaymentQuery false;
  156.         $addAddressQuery false;
  157.         $addNoteTitleQuery false;
  158.         $qb $this->createQueryBuilder('c');
  159.         $groupsWhereExpr $qb->expr()->orX();
  160.         $managingDirectorsWhereExpr $qb->expr()->orX();
  161.         $accountantsWhereExpr $qb->expr()->orX();
  162.         $authorizedAccountantsWhereExpr $qb->expr()->orX();
  163.         if (true === $isCount) {
  164.             $qb->select($qb->expr()->countDistinct('c.id'));
  165.         } else {
  166.             $qb->groupBy('c.id');
  167.             if (null !== $limit) {
  168.                 $qb->setMaxResults($limit);
  169.             }
  170.             if (null !== $offset) {
  171.                 $qb->setFirstResult($offset);
  172.             }
  173.             $addContactEmailQuery true;
  174.         }
  175.         if (false === empty($criteria)) {
  176.             foreach ($criteria as $criterion => $values) {
  177.                 if (true === empty($values)) {
  178.                     continue;
  179.                 }
  180.                 if ('search' === $criterion) {
  181.                     $searchTokens array_filter(explode(' '$values), function (mixed $value) {
  182.                         return ' ' !== $value;
  183.                     });
  184.                     $expression $qb->expr()->orX(
  185.                         $qb->expr()->like('c.name'':search'),
  186.                         $qb->expr()->like('c.oldName'':search'),
  187.                         $qb->expr()->like('c.phone'':search'),
  188.                         $qb->expr()->like('c.secondaryPhone'':search'),
  189.                         $qb->expr()->like('ce.email'':search'),
  190.                         $qb->expr()->like('ce.secondaryEmail'':search'),
  191.                         $qb->expr()->like('c.registrationNumber'':search'),
  192.                         $qb->expr()->like('c.idNumber'':search'),
  193.                         $qb->expr()->like('c.norwegianIdNumber'':search'),
  194.                         $qb->expr()->like('c.norwegianTemporaryIdNumber'':search'),
  195.                     );
  196.                     $nameExpression $qb->expr()->andX();
  197.                     foreach ($searchTokens as $key => $searchToken) {
  198.                         $paramKey 'search_' $key;
  199.                         $nameExpression->add(
  200.                             $qb->expr()->orX(
  201.                                 $qb->expr()->like('c.firstName'':' $paramKey),
  202.                                 $qb->expr()->like('c.lastName'':' $paramKey)
  203.                             )
  204.                         );
  205.                         $qb->setParameter($paramKey'%' $searchToken '%');
  206.                     }
  207.                     $expression->add($nameExpression);
  208.                     if (true === $isCount) {
  209.                         $qb->andWhere($expression);
  210.                     } else {
  211.                         $qb->having($expression);
  212.                     }
  213.                     $qb->setParameter('search''%' $values '%');
  214.                     $addFullNameQuery true;
  215.                     $addContactEmailQuery true;
  216.                 }
  217.                 if ('type' === $criterion) {
  218.                     if (true === \is_array($values)) {
  219.                         $qb->andWhere($qb->expr()->in('c.type'':type'));
  220.                     } else {
  221.                         $qb->andWhere($qb->expr()->eq('c.type'':type'));
  222.                     }
  223.                     $qb->setParameter('type'$values);
  224.                 }
  225.                 if ('relationshipCustomerSupplier' === $criterion) {
  226.                     $addRelationshipCustomerSupplierQuery true;
  227.                 }
  228.                 if ('employmentRelationship' === $criterion) {
  229.                     $addEmploymentRelationshipQuery true;
  230.                 }
  231.                 if ('notificationInvoicePayment' === $criterion) {
  232.                     $addNotificationInvoicePaymentQuery true;
  233.                 }
  234.                 if ('forSale' === $criterion) {
  235.                     $qb->andWhere($qb->expr()->eq('c.forSale'':forSale'));
  236.                     $qb->setParameter('forSale'true);
  237.                 }
  238.                 if ('country' === $criterion) {
  239.                     $countryWhereExpr $qb->expr()->orX();
  240.                     foreach ($values as $key => $value) {
  241.                         $paramKey 'country_' $key;
  242.                         $countryWhereExpr->add($qb->expr()->eq('ca.country'':' $paramKey));
  243.                         $qb->setParameter($paramKey$value);
  244.                     }
  245.                     $qb->andWhere($countryWhereExpr);
  246.                     $addAddressQuery true;
  247.                 }
  248.                 if ('gender' === $criterion) {
  249.                     $genderWhereExpr $qb->expr()->orX();
  250.                     foreach ($values as $key => $value) {
  251.                         $paramKey 'gender_' $key;
  252.                         $genderWhereExpr->add($qb->expr()->eq('c.gender'':' $paramKey));
  253.                         $qb->setParameter($paramKey$valueGenderType::NAME);
  254.                     }
  255.                     $qb->andWhere($genderWhereExpr);
  256.                 }
  257.                 if ('group' === $criterion) {
  258.                     foreach ($values as $key => $value) {
  259.                         $paramKey 'groupId_' $key;
  260.                         $groupsWhereExpr->add($qb->expr()->eq('cgi.group'':' $paramKey));
  261.                         $qb->setParameter($paramKey$valueGroupIdType::NAME);
  262.                     }
  263.                     $qb->andWhere($groupsWhereExpr);
  264.                     $addGroupQuery true;
  265.                 }
  266.                 if ('managingDirector' === $criterion) {
  267.                     foreach ($values as $key => $value) {
  268.                         $paramKey 'managingDirectorId_' $key;
  269.                         $managingDirectorsWhereExpr->add($qb->expr()->eq('cr_md.managingDirector'':' $paramKey));
  270.                         $qb->setParameter($paramKey$valueContactIdType::NAME);
  271.                     }
  272.                     $qb->andWhere($managingDirectorsWhereExpr);
  273.                     $addManagingDirectorQuery true;
  274.                 }
  275.                 if ('accountant' === $criterion) {
  276.                     foreach ($values as $key => $value) {
  277.                         $paramKey 'accountantId_' $key;
  278.                         $accountantsWhereExpr->add($qb->expr()->eq('cr_a.accountant'':' $paramKey));
  279.                         $qb->setParameter($paramKey$valueContactIdType::NAME);
  280.                     }
  281.                     $qb->andWhere($accountantsWhereExpr);
  282.                     $addAccountantQuery true;
  283.                 }
  284.                 if ('authorizedAccountant' === $criterion) {
  285.                     foreach ($values as $key => $value) {
  286.                         $paramKey 'authorizedAccountantId_' $key;
  287.                         $authorizedAccountantsWhereExpr->add($qb->expr()->eq('cr_aa.authorizedAccountant'':' $paramKey));
  288.                         $qb->setParameter($paramKey$valueContactIdType::NAME);
  289.                     }
  290.                     $qb->andWhere($authorizedAccountantsWhereExpr);
  291.                     $addAuthorizedAccountantQuery true;
  292.                 }
  293.                 if ('language' === $criterion) {
  294.                     $languageWhereExpr $qb->expr()->orX();
  295.                     foreach ($values as $key => $value) {
  296.                         $paramKey 'language_' $key;
  297.                         $languageWhereExpr->add($qb->expr()->eq('c.language'':' $paramKey));
  298.                         $qb->setParameter($paramKey$value);
  299.                     }
  300.                     $qb->andWhere($languageWhereExpr);
  301.                 }
  302.                 if ('workOccupation' === $criterion) {
  303.                     $workOccupationWhereExpr $qb->expr()->orX();
  304.                     foreach ($values as $key => $value) {
  305.                         $paramKey 'workOccupationId_' $key;
  306.                         $workOccupationWhereExpr->add($qb->expr()->eq('c.workOccupation'':' $paramKey));
  307.                         $qb->setParameter($paramKey$valueWorkOccupationType::NAME);
  308.                     }
  309.                     $qb->andWhere($workOccupationWhereExpr);
  310.                 }
  311.                 if ('industrySector' === $criterion) {
  312.                     $industrySectorWhereExpr $qb->expr()->orX();
  313.                     foreach ($values as $key => $value) {
  314.                         $paramKey 'industrySector_' $key;
  315.                         $industrySectorWhereExpr->add($qb->expr()->eq('c.industrySector'':' $paramKey));
  316.                         $qb->setParameter($paramKey$valueIndustrySectorType::NAME);
  317.                     }
  318.                     $qb->andWhere($industrySectorWhereExpr);
  319.                 }
  320.                 if ('maritalStatus' === $criterion) {
  321.                     $maritalStatusWhereExpr $qb->expr()->orX();
  322.                     foreach ($values as $key => $value) {
  323.                         $paramKey 'maritalStatus_' $key;
  324.                         $maritalStatusWhereExpr->add($qb->expr()->eq('c.maritalStatus'':' $paramKey));
  325.                         $qb->setParameter($paramKey$valueMaritalStatusType::NAME);
  326.                     }
  327.                     $qb->andWhere($maritalStatusWhereExpr);
  328.                 }
  329.                 if ('nationality' === $criterion) {
  330.                     $nationalityWhereExpr $qb->expr()->orX();
  331.                     foreach ($values as $key => $value) {
  332.                         $paramKey 'nationality_' $key;
  333.                         $nationalityWhereExpr->add($qb->expr()->eq('c.nationality'':' $paramKey));
  334.                         $qb->setParameter($paramKey$value);
  335.                     }
  336.                     $qb->andWhere($nationalityWhereExpr);
  337.                 }
  338.                 if ('vatActivity' === $criterion) {
  339.                     if (true === $values) {
  340.                         $qb->andWhere($qb->expr()->isNotNull('c.vatin'));
  341.                     }
  342.                 }
  343.                 if ('vatActivityNone' === $criterion) {
  344.                     if (true === $values) {
  345.                         $qb->andWhere($qb->expr()->isNull('c.vatin'));
  346.                     }
  347.                 }
  348.                 if ('noteTitle' === $criterion) {
  349.                     $noteTitleWhereExpr $qb->expr()->orX();
  350.                     foreach ($values as $key => $value) {
  351.                         $paramKey 'note_title_' $key;
  352.                         $noteTitleWhereExpr->add($qb->expr()->eq('n.title'':' $paramKey));
  353.                         $qb->setParameter($paramKey$value);
  354.                     }
  355.                     $qb->andWhere($noteTitleWhereExpr);
  356.                     $addNoteTitleQuery true;
  357.                 }
  358.             }
  359.         }
  360.         if (false === $isCount) {
  361.             if (false === empty($orderBy)) {
  362.                 foreach ($orderBy as $column => $direction) {
  363.                     if ('fullName' === $column) {
  364.                         $qb->addOrderBy('fullName'$direction);
  365.                         $addFullNameQuery true;
  366.                     }
  367.                     if ('phone' === $column) {
  368.                         $qb->addOrderBy('c.phone'$direction);
  369.                     }
  370.                     if ('email' === $column) {
  371.                         $qb->addOrderBy('ce.email'$direction);
  372.                         $addContactEmailQuery true;
  373.                     }
  374.                 }
  375.             }
  376.         }
  377.         if (true === $addFullNameQuery && false === $isCount) {
  378.             $qb
  379.                 ->addSelect(
  380.                     "CASE WHEN c.type = 1 THEN c.name WHEN c.type = 2 THEN CONCAT(c.lastName, ' ', c.firstName) ELSE '' END AS HIDDEN fullName"
  381.                 )
  382.             ;
  383.         }
  384.         if (true === $addContactEmailQuery) {
  385.             if (false === $isCount) {
  386.                 $qb->addSelect('ce');
  387.             }
  388.             $qb
  389.                 ->innerJoin('c.contactEmail''ce'Join::WITH$qb->expr()->eq('c.contactEmail''ce.id'))
  390.             ;
  391.         }
  392.         $qb
  393.             ->innerJoin(ContactPermissionInterface::class, 'cp'Join::WITH$qb->expr()->andX(
  394.                 $qb->expr()->eq('cp.contact''c.id'),
  395.                 $qb->expr()->eq('cp.authorizedContact'':id')
  396.             ))
  397.         ;
  398.         if (true === $addAddressQuery) {
  399.             $qb
  400.                 ->innerJoin(ContactAddressInterface::class, 'ca'Join::WITH$qb->expr()->andX(
  401.                     $qb->expr()->eq('ca.id''c.contactAddress')
  402.                 ))
  403.             ;
  404.         }
  405.         if (true === $addGroupQuery) {
  406.             $qb
  407.                 ->innerJoin(GroupItemInterface::class, 'cgi'Join::WITH$qb->expr()->andX(
  408.                     $qb->expr()->eq('cgi.contact''c.id')
  409.                 ))
  410.             ;
  411.         }
  412.         if (true === $addManagingDirectorQuery) {
  413.             $qb
  414.                 ->innerJoin(ManagingDirectorInterface::class, 'cr_md'Join::WITH$qb->expr()->andX(
  415.                     $qb->expr()->eq('cr_md.contact''c.id')
  416.                 ))
  417.             ;
  418.         }
  419.         if (true === $addAccountantQuery) {
  420.             $qb
  421.                 ->innerJoin(AccountantInterface::class, 'cr_a'Join::WITH$qb->expr()->andX(
  422.                     $qb->expr()->eq('cr_a.contact''c.id')
  423.                 ))
  424.             ;
  425.         }
  426.         if (true === $addAuthorizedAccountantQuery) {
  427.             $qb
  428.                 ->innerJoin(AuthorizedAccountantInterface::class, 'cr_aa'Join::WITH$qb->expr()->andX(
  429.                     $qb->expr()->eq('cr_aa.contact''c.id')
  430.                 ))
  431.             ;
  432.         }
  433.         if (true === $addEmploymentRelationshipQuery) {
  434.             $qb
  435.                 ->innerJoin(EmploymentInterface::class, 'cer'Join::WITH$qb->expr()->andX(
  436.                     $qb->expr()->eq('cer.employer''cp.authorizedContact'),
  437.                     $qb->expr()->eq('cer.employee''cp.contact')
  438.                 ))
  439.             ;
  440.         }
  441.         if (true === $addRelationshipCustomerSupplierQuery) {
  442.             $qb
  443.                 ->innerJoin(ContactRelationshipCustomerSupplierInterface::class, 'ccr'Join::WITH$qb->expr()->andX(
  444.                     $qb->expr()->eq('ccr.supplier''cp.authorizedContact'),
  445.                     $qb->expr()->eq('ccr.customer''cp.contact')
  446.                 ))
  447.             ;
  448.         }
  449.         if (true === $addNotificationInvoicePaymentQuery) {
  450.             $qb
  451.                 ->innerJoin(InvoicePaymentNotificationInterface::class, 'ipn'Join::WITH$qb->expr()->andX(
  452.                     $qb->expr()->eq('ipn.supplier'':id'),
  453.                     $qb->expr()->eq('ipn.customer''c.id')
  454.                 ))
  455.             ;
  456.         }
  457.         if (true === $addNoteTitleQuery) {
  458.             $qb
  459.                 ->innerJoin(NoteInterface::class, 'n'Join::WITH$qb->expr()->andX(
  460.                     $qb->expr()->eq('n.contact''c.id')
  461.                 ))
  462.                 ->innerJoin(NotePermissionInterface::class, 'np'Join::WITH$qb->expr()->andX(
  463.                     $qb->expr()->eq('n.id''np.note'),
  464.                     $qb->expr()->eq('np.contact'':id')
  465.                 ))
  466.             ;
  467.         }
  468.         $qb->setParameter('id'$idContactIdType::NAME);
  469.         return $qb;
  470.     }
  471. }