<?php
namespace Cms\ModuleBundle\Model;
use App\Entity\Shared\UlidIdentifiableInterface;
use App\Entity\Shared\UlidTransitionalInterface;
use Cms\ContainerBundle\Entity\Container;
use Cms\CoreBundle\Service\StringUtils\LoremIpsumGenerator;
use Cms\CoreBundle\Util\Doctrine\EntityManager;
use Cms\FrontendBundle\Model\FrontendGlobals;
use Cms\ModuleBundle\Doctrine\ProxyRepository;
use Cms\ModuleBundle\Entity\ModuleSettings;
use Cms\ModuleBundle\Entity\Proxy;
use Cms\TagBundle\Model\Taggable\TaggableModuleRepositoryInterface;
use Cms\WidgetBundle\Model\AbstractWidgetProcessor;
use Cms\WidgetBundle\Model\ModuleLimitedListWidgetProcessorInterface;
use Cms\WidgetBundle\Model\WidgetObject;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr;
use Doctrine\ORM\QueryBuilder;
use ReflectionClass;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Ulid\Ulid;
/**
* Class AbstractModuleListWidgetProcessor
* @package Cms\ModuleBundle\Model
*/
abstract class AbstractModuleListWidgetProcessor extends AbstractWidgetProcessor
{
/**
* @var LoremIpsumGenerator
*/
protected $lipsum = null;
/**
* @var EntityManager
*/
protected $em = null;
/**
* @return Expr
*/
protected function expr()
{
return $this->em->getExpressionBuilder();
}
/**
* @param string $class
* @param callable $callback
* @param int $count
* @return array|Proxy[]
*/
protected function samples($class, callable $callback, $count = null)
{
if (empty($count) || intval($count) <= 0 || intval($count) > 24) {
$count = 9;
}
$refl = new ReflectionClass($class);
$samples = [];
for ($i = 0; $i < $count; $i++) {
$samples[] = $sample = $callback(new $class(), $i);
switch (true) {
case $sample instanceof UlidIdentifiableInterface:
$sample->setId(Ulid::generate(true));
break;
case $sample instanceof UlidTransitionalInterface:
$sample->setUlid(Ulid::generate(true));
break;
default:
$prop = $refl->getProperty('id');
$prop->setAccessible(true);
$prop->setValue($sample, $i);
}
}
return $samples;
}
/**
* {@inheritdoc}
*/
public function setup(ContainerInterface $container)
{
parent::setup($container);
$this->lipsum = $container->get(LoremIpsumGenerator::class);
$this->em = $container->get(EntityManager::class);
}
/**
* @param string $class
* @param QueryBuilder $qb
* @param WidgetObject $object
* @return array|Proxy[]
*/
protected function query($class, QueryBuilder $qb, WidgetObject $object)
{
if ( ! $class instanceof EntityRepository) {
$repo = $this->repo($class);
} else {
$repo = $class;
}
$limit = 9;
if ($this instanceof ModuleLimitedListWidgetProcessorInterface) {
$limit = $this->getLimit($object);
}
return $repo->queryMany($qb, $limit);
}
/**
* @param WidgetObject $object
* @param FrontendGlobals $globals
* @return array|Container[]
*/
protected function determineContainers(WidgetObject $object, FrontendGlobals $globals)
{
if ($object->getId() === null || ($globals->getContainer() !== null && intval($object->getId()) === $globals->getContainer()->getId())) {
$container = $globals->getContainer();
} else {
switch ($object->getId()) {
case 'dynamic':
$container = $globals->getContainer();
break;
default:
$container = $this->em->getRepository(Container::class)->findExact(
intval($object->getId())
);
}
}
if ($container === $globals->getContainer()) {
return $globals->getContainers();
} else {
$ancestors = $this->em->getRepository(Container::class)->findAncestors($container);
$ancestors[] = $container;
return array_reverse($ancestors);
}
}
/**
* @param string $class
* @return ProxyRepository|TaggableModuleRepositoryInterface
*/
protected function repo($class)
{
return $this->em->getRepository($class);
}
/**
* @param string $class
* @param int|array|Container|int[]|Container[] $container
* @param array $tags
* @param bool|null $deep
* @return QueryBuilder
*/
protected function qb(
string $class,
$container,
array $tags = [],
?bool $deep = null
): QueryBuilder
{
/** @var ProxyRepository $repo */
$repo = $this->repo($class);
$qb = $repo->createQueryBuilder('proxy');
if ($deep === true) {
// TODO: need to fix this to be compatible with cross dept sharing...
$qb
->andWhere($qb->expr()->in(
'proxy.id',
$this->em->createQueryBuilder()
// TODO: take into account sharing
->select('DISTINCT IDENTITY(shares.sharedProxy)')
->from($class, 'shares')
->leftJoin('shares.container', 'containerr')
// TODO: To get children we need root to be equal, not GREATER or equal, isn't it?
->andWhere('containerr.rt >= :rt')
->andWhere('containerr.lft >= :lft')
->andWhere('containerr.rgt <= :rgt')
->getDQL()
))
->setParameter('rt', $container->getRoot())
->setParameter('lft', $container->getLeft())
->setParameter('rgt', $container->getRight())
->leftJoin('proxy.container', 'container');
} else {
$qb
->andWhere('proxy.container IN (:container)')
->setParameter(
'container',
($container instanceof Container) ? array($container->getId()) : $container
);
}
if ($this->repo($class) instanceof TaggableModuleRepositoryInterface && ! empty($tags)) {
$qb = $this->repo($class)->filterByTags($qb, $tags);
}
return $qb;
}
}