src/Cms/ContainerBundle/Doctrine/ContainerRepository.php line 188

Open in your IDE?
  1. <?php
  2. namespace Cms\ContainerBundle\Doctrine;
  3. use Cms\ContainerBundle\Entity\Container;
  4. use Cms\ContainerBundle\Entity\Containers\GenericContainer;
  5. use Cms\ContainerBundle\Entity\Containers\IntranetContainer;
  6. use Cms\ContainerBundle\Entity\Containers\PersonalContainer;
  7. use Cms\ContainerBundle\Entity\Containers\StorageContainer;
  8. use Cms\CoreBundle\Util\Doctrine\EntityRepository;
  9. use Cms\TenantBundle\Entity\Tenant;
  10. use Doctrine\Common\Collections\Criteria;
  11. use Doctrine\ORM\QueryBuilder;
  12. use Platform\SecurityBundle\Entity\Identity\Account;
  13. /**
  14.  * Class ContainerRepository
  15.  * @package Cms\ContainerBundle\Doctrine
  16.  *
  17.  * @method Container findExact($id)
  18.  * @method Container find($id)
  19.  * @method array|Container[] findAll()
  20.  */
  21. class ContainerRepository extends EntityRepository
  22. {
  23.     /**
  24.      * @param Container $root
  25.      * @param string|null $path
  26.      * @return array|Container[]
  27.      */
  28.     public function findByPath(Container $root, ?string $path): array
  29.     {
  30.         // normalize path
  31.         $path trim($path'/'); // trim slashes from front and back
  32.         $path preg_replace('/\/+/''/'$path); // replace multiple slashes with one
  33.         $path $path ?: null;
  34.         // if no path, nothing to return
  35.         if ( ! $path) {
  36.             return [$root];
  37.         }
  38.         // break apart the path
  39.         $slugs explode('/'$path);
  40.         // start finding the containers
  41.         $departments = [
  42.             $root// we include the root as the first department
  43.         ];
  44.         // loop over the slugs
  45.         foreach ($slugs as $slug) {
  46.             // try to find current one
  47.             $department $this->findOneBy([
  48.                 'parent' => $departments[count($departments) - 1],
  49.                 'slug' => $slug,
  50.             ]);
  51.             // if it is not found, the path is bad
  52.             if ( ! $department) {
  53.                 return [];
  54.             }
  55.             // we did find one, add it to the set
  56.             $departments[] = $department;
  57.         }
  58.         return $departments;
  59.     }
  60.     /**
  61.      * @return Container
  62.      * @throws \Exception
  63.      */
  64.     public function findOneForRendering()
  65.     {
  66.         $containers $this->queryMany($this->createQueryBuilder('container')
  67.             ->andWhere('container.parent IS NULL')
  68.             ->orderBy('container.id''ASC')
  69.         );
  70.         if (count($containers) < 1) {
  71.             throw new \Exception();
  72.         }
  73.         foreach ($containers as $container) {
  74.             if ($container instanceof GenericContainer) {
  75.                 return $container;
  76.             }
  77.         }
  78.         return $containers[0];
  79.     }
  80.     /**
  81.      * @param Tenant $tenant
  82.      * @param Container $parent
  83.      * @return array|Container[]
  84.      */
  85.     public function findAllForTenant(Tenant $tenantContainer $parent null)
  86.     {
  87.         $qb $this->createQueryBuilder('containers');
  88.         $qb
  89.             ->andWhere('containers.tenant = :tenant')
  90.             ->setParameter('tenant'$tenant);
  91.         if ($parent !== null) {
  92.             $qb
  93.                 ->andWhere('containers.parent = :parent')
  94.                 ->setParameter('parent'$parent);
  95.         } else {
  96.             $qb->andWhere('containers.parent IS NULL');
  97.         }
  98.         return $this->queryMany($qb);
  99.     }
  100.     /**
  101.      * TODO: this method has become overloaded and needs refactored and improved
  102.      *
  103.      * @param Container|null $subtree
  104.      * @param array|string[] $types
  105.      * @param Account|null $account
  106.      * @return QueryBuilder
  107.      */
  108.     public function findAllHierarchyQb(Container $subtree null, array $types = [], ?Account $account null): QueryBuilder
  109.     {
  110.         $qb $this->createQueryBuilder('containers');
  111.         if ( ! empty($subtree)) {
  112.             $qb
  113.                 ->andWhere('containers.rt = :root')
  114.                 ->setParameter('root'$subtree->getRoot());
  115.         } else {
  116.             $qb
  117.                 ->leftJoin($this->getClassName(), 'roots''WITH''containers.rt = roots.id')
  118.                 ->addSelect('CASE WHEN roots INSTANCE OF :generic THEN 0 WHEN roots INSTANCE OF :intranet THEN 1 WHEN roots INSTANCE OF :personal THEN 2 WHEN roots INSTANCE OF :storage THEN 3 ELSE 4 END AS HIDDEN searchOrder')
  119.                 ->setParameter('generic'GenericContainer::DISCR)
  120.                 ->setParameter('intranet'IntranetContainer::DISCR)
  121.                 ->setParameter('personal'PersonalContainer::DISCR)
  122.                 ->setParameter('storage'StorageContainer::DISCR)
  123.                 ->addOrderBy('searchOrder''ASC')
  124.                 ->addOrderBy('roots.name''ASC');
  125.         }
  126.         if ( ! empty($types)) {
  127.             $ors = [];
  128.             foreach ($types as $index => $type) {
  129.                 $ors[] = $qb->expr()->isInstanceOf('containers'$type);
  130.             }
  131.             $qb->andWhere(call_user_func_array([$qb->expr(), 'orX'], $ors));
  132.             if (in_array(PersonalContainer::class, $types) && ! empty($account)) {
  133.                 $qb
  134.                     ->andWhere('roots.account = :account')
  135.                     ->setParameter('account'$account);
  136.             }
  137.         }
  138.         $qb
  139.             ->addOrderBy('containers.rt''ASC')
  140.             ->addOrderBy('containers.lft''ASC');
  141.         return $qb;
  142.     }
  143.     /**
  144.      * @param Container|null $subtree
  145.      * @param array|string[] $types
  146.      * @param Account|null $account
  147.      * @return array|Container[]
  148.      */
  149.     public function findAllHierarchy(Container $subtree null, array $types = [], ?Account $account null): array
  150.     {
  151.         return $this->queryMany($this->findAllHierarchyQb($subtree$types$account));
  152.     }
  153.     /**
  154.      * @return array|Container[]
  155.      */
  156.     public function findAllRoots()
  157.     {
  158.         // create builder
  159.         $qb $this->createQueryBuilder('containers');
  160.         // filter by site
  161.         $qb
  162.             ->andWhere('containers.parent IS NULL');
  163.         // order by left value, then by name
  164.         $qb
  165.             ->addOrderBy('containers.name''ASC');
  166.         // run
  167.         return $this->queryMany($qb);
  168.     }
  169.     /**
  170.      * @param Container $container
  171.      * @return array|Container[]
  172.      */
  173.     public function findAncestors(Container $container)
  174.     {
  175.         // create builder
  176.         $qb $this->createQueryBuilder('containers');
  177.         // make sure we stay in our root
  178.         $qb
  179.             ->andWhere('containers.rt = :root')
  180.             ->setParameter('root'$container->getRoot());
  181.         // use left/right anomaly to filter
  182.         // TODO: if we stay in our root, can we just use the level instead of left/right???
  183.         $qb
  184.             ->andWhere('containers.lft < :left')
  185.             ->setParameter('left'$container->getLeft())
  186.             ->andWhere('containers.rgt > :right')
  187.             ->setParameter('right'$container->getRight());
  188.         // order with furthest ancestor first
  189.         $qb->addOrderBy('containers.lft''ASC');
  190.         // run
  191.         return $this->queryMany($qb);
  192.     }
  193.     /**
  194.      * @param Container $container
  195.      * @return array|Container[]
  196.      */
  197.     public function findDescendants(Container $container)
  198.     {
  199.         // create builder
  200.         $qb $this->createQueryBuilder('containers');
  201.         // make sure we stay in our root
  202.         $qb
  203.             ->andWhere('containers.rt = :root')
  204.             ->setParameter('root'$container->getRoot());
  205.         // use left/right anomaly to filter
  206.         // TODO: if we stay in our root, can we just use the level instead of left/right???
  207.         $qb
  208.             ->andWhere('containers.lft > :left')
  209.             ->setParameter('left'$container->getLeft())
  210.             ->andWhere('containers.rgt < :right')
  211.             ->setParameter('right'$container->getRight());
  212.         // order with furthest ancestor first
  213.         $qb->addOrderBy('containers.lft''ASC');
  214.         // run
  215.         return $this->queryMany($qb);
  216.     }
  217.     /**
  218.      * @param Container $container
  219.      * @param int $limit
  220.      * @param int $page
  221.      * @return array
  222.      */
  223.     public function findManyChildren(Container $container$limit 0$page 0)
  224.     {
  225.         $queryBuilder =
  226.             $this
  227.                 ->createQueryBuilder('container')
  228.                 ->andWhere('container.parent = :parent')->setParameter('parent'$container)
  229.                 ->orderBy('container.name''ASC');
  230.         return $this->queryMany($queryBuilder$limit$page);
  231.     }
  232.     /**
  233.      * Get all containers with specified ID or name
  234.      *
  235.      * @param mixed $value
  236.      * @return array|Container[]
  237.      */
  238.     public function findAllByIdOrName($value)
  239.     {
  240.         $value strval($value);
  241.         if (preg_match('/^[1-9]\d*$/'$value) === 1) {
  242.             return $this->findBy(array(
  243.                 'id' => intval($value),
  244.             ));
  245.         }
  246.         return $this->findBy(array(
  247.             'name' => $value,
  248.         ));
  249.     }
  250.     /**
  251.      * @param Container $container
  252.      * @param string $module
  253.      * @return array|Container[]
  254.      */
  255.     public function findModuleViewableHierarchy(Container $container$module)
  256.     {
  257.         return $this->findViewableHierarchy(
  258.             $container,
  259.             (new Criteria())
  260.                 ->andWhere(Criteria::expr()->eq(
  261.                     sprintf(
  262.                         'containers.moduleFlags.%s',
  263.                         $module
  264.                     ),
  265.                     true
  266.                 ))
  267.                 ->orderBy(array(
  268.                     'containers.name' => 'ASC',
  269.                 ))
  270.         );
  271.     }
  272.     /**
  273.      * @param Container $container
  274.      * @param string $module
  275.      * @return array|Container[]
  276.      */
  277.     public function findModuleViewableHierarchySettings(Container $container$module)
  278.     {
  279.         return $this->findViewableHierarchy(
  280.             $container,
  281.             (new Criteria())
  282.                 ->andWhere(Criteria::expr()->eq(
  283.                     sprintf(
  284.                         'containers.moduleFlags.%s',
  285.                         $module
  286.                     ),
  287.                     true
  288.                 ))
  289.                 ->orderBy(array(
  290.                     'containers.rt' => 'ASC',
  291.                     'containers.lft' => 'ASC',
  292.                     'containers.name' => 'ASC',
  293.                 ))
  294.         );
  295.     }
  296.     /**
  297.      * @param Container $container
  298.      * @param Criteria $criteria
  299.      * @return array|Container[]
  300.      */
  301.     public function findViewableHierarchy(Container $containerCriteria $criteria null)
  302.     {
  303.         // create builder
  304.         $qb $this->createQueryBuilder('containers');
  305.         // make sure we stay in our root
  306.         $qb
  307.             ->andWhere('containers.rt = :root')
  308.             ->setParameter('root'$container->getRoot());
  309.         // use left/right anomaly to filter
  310.         // TODO: if we stay in our root, can we just use the level instead of left/right???
  311.         $qb
  312.             ->andWhere('containers.lft >= :left')
  313.             ->setParameter('left'$container->getLeft())
  314.             ->andWhere('containers.rgt <= :right')
  315.             ->setParameter('right'$container->getRight())
  316.             ->andWhere('containers.hidden = :hidden')
  317.             ->setParameter('hidden'false)
  318.         ;
  319.         // order with furthest ancestor first
  320.         $qb->addOrderBy('containers.lft''ASC');
  321.         // apply criteria
  322.         if ( ! empty($criteria)) {
  323.             $qb->resetDQLPart('orderBy');
  324.             $qb->addCriteria($criteria);
  325.         }
  326.         // run
  327.         return $this->queryMany($qb);
  328.     }
  329.     /**
  330.      *  Soft search and ignoring of missed things
  331.      * @param array $ids
  332.      * @return Container[]
  333.      */
  334.     public function searchContainers($ids = [])
  335.     {
  336.         $qb $this->createQueryBuilder('containers')
  337.             ->andWhere('containers.id IN (:ids)')
  338.             ->setParameter('ids'$ids);
  339.         /** @var Container[] $results */
  340.         $results $this->queryMany($qb);
  341.         $fixed = [];
  342.         foreach ($results as $result) {
  343.             $fixed[$result->getId()] = $result;
  344.         }
  345.         return $results;
  346.     }
  347. }