Added filter possibility to attachment list

This commit is contained in:
Jan Böhmer 2022-09-11 02:00:22 +02:00
parent bee057bc4b
commit 017b0f717e
8 changed files with 440 additions and 2 deletions

View file

@ -44,12 +44,14 @@ namespace App\DataTables;
use App\DataTables\Column\LocaleDateTimeColumn;
use App\DataTables\Column\PrettyBoolColumn;
use App\DataTables\Filters\AttachmentFilter;
use App\Entity\Attachments\Attachment;
use App\Services\Attachments\AttachmentManager;
use App\Services\Attachments\AttachmentURLGenerator;
use App\Services\ElementTypeNameGenerator;
use App\Services\EntityURLGenerator;
use Doctrine\ORM\QueryBuilder;
use Omines\DataTablesBundle\Adapter\Doctrine\ORM\SearchCriteriaProvider;
use Omines\DataTablesBundle\Adapter\Doctrine\ORMAdapter;
use Omines\DataTablesBundle\Column\TextColumn;
use Omines\DataTablesBundle\DataTable;
@ -213,6 +215,12 @@ final class AttachmentDataTable implements DataTableTypeInterface
'query' => function (QueryBuilder $builder): void {
$this->getQuery($builder);
},
'criteria' => [
function (QueryBuilder $builder) use ($options): void {
$this->buildCriteria($builder, $options);
},
new SearchCriteriaProvider(),
],
]);
}
@ -225,4 +233,18 @@ final class AttachmentDataTable implements DataTableTypeInterface
->leftJoin('attachment.attachment_type', 'attachment_type');
//->leftJoin('attachment.element', 'element');
}
private function buildCriteria(QueryBuilder $builder, array $options): void
{
//We do the most stuff here in the filter class
if (isset($options['filter'])) {
if(!$options['filter'] instanceof AttachmentFilter) {
throw new \Exception('filter must be an instance of AttachmentFilter!');
}
$filter = $options['filter'];
$filter->apply($builder);
}
}
}

View file

@ -0,0 +1,120 @@
<?php
namespace App\DataTables\Filters;
use App\DataTables\Filters\Constraints\BooleanConstraint;
use App\DataTables\Filters\Constraints\DateTimeConstraint;
use App\DataTables\Filters\Constraints\EntityConstraint;
use App\DataTables\Filters\Constraints\InstanceOfConstraint;
use App\DataTables\Filters\Constraints\NumberConstraint;
use App\DataTables\Filters\Constraints\TextConstraint;
use App\Entity\Attachments\AttachmentType;
use App\Services\Trees\NodesListBuilder;
use Doctrine\ORM\QueryBuilder;
class AttachmentFilter implements FilterInterface
{
use CompoundFilterTrait;
/** @var NumberConstraint */
protected $dbId;
/** @var InstanceOfConstraint */
protected $targetType;
/** @var TextConstraint */
protected $name;
/** @var EntityConstraint */
protected $attachmentType;
/** @var BooleanConstraint */
protected $showInTable;
/** @var DateTimeConstraint */
protected $lastModified;
/** @var DateTimeConstraint */
protected $addedDate;
public function __construct(NodesListBuilder $nodesListBuilder)
{
$this->dbId = new NumberConstraint('attachment.id');
$this->name = new TextConstraint('attachment.name');
$this->targetType = new InstanceOfConstraint('attachment');
$this->attachmentType = new EntityConstraint($nodesListBuilder, AttachmentType::class, 'attachment.attachment_type');
$this->lastModified = new DateTimeConstraint('attachment.lastModified');
$this->addedDate = new DateTimeConstraint('attachment.addedDate');
$this->showInTable = new BooleanConstraint('attachment.show_in_table');
}
public function apply(QueryBuilder $queryBuilder): void
{
$this->applyAllChildFilters($queryBuilder);
}
/**
* @return NumberConstraint
*/
public function getDbId(): NumberConstraint
{
return $this->dbId;
}
/**
* @return TextConstraint
*/
public function getName(): TextConstraint
{
return $this->name;
}
/**
* @return DateTimeConstraint
*/
public function getLastModified(): DateTimeConstraint
{
return $this->lastModified;
}
/**
* @return DateTimeConstraint
*/
public function getAddedDate(): DateTimeConstraint
{
return $this->addedDate;
}
/**
* @return BooleanConstraint
*/
public function getShowInTable(): BooleanConstraint
{
return $this->showInTable;
}
/**
* @return EntityConstraint
*/
public function getAttachmentType(): EntityConstraint
{
return $this->attachmentType;
}
/**
* @return InstanceOfConstraint
*/
public function getTargetType(): InstanceOfConstraint
{
return $this->targetType;
}
}

View file

@ -0,0 +1,96 @@
<?php
namespace App\DataTables\Filters\Constraints;
use Doctrine\ORM\QueryBuilder;
/**
* This constraint allows to filter by a given list of classes, that the given property should be an instance of
*/
class InstanceOfConstraint extends AbstractConstraint
{
public const ALLOWED_OPERATOR_VALUES = ['ANY', 'NONE'];
/**
* @var string[] The values to compare to (fully qualified class names)
*/
protected $value;
/**
* @var string The operator to use
*/
protected $operator;
/**
* @return string[]
*/
public function getValue(): array
{
return $this->value;
}
/**
* @param string[] $value
* @return $this
*/
public function setValue(array $value): self
{
$this->value = $value;
return $this;
}
/**
* @return string
*/
public function getOperator(): string
{
return $this->operator;
}
/**
* @param string $operator
* @return $this
*/
public function setOperator(string $operator): self
{
$this->operator = $operator;
return $this;
}
public function isEnabled(): bool
{
return !empty($this->operator);
}
public function apply(QueryBuilder $queryBuilder): void
{
//If no value is provided then we do not apply a filter
if (!$this->isEnabled()) {
return;
}
//Ensure we have an valid operator
if(!in_array($this->operator, self::ALLOWED_OPERATOR_VALUES, true)) {
throw new \RuntimeException('Invalid operator '. $this->operator . ' provided. Valid operators are '. implode(', ', self::ALLOWED_OPERATOR_VALUES));
}
$expressions = [];
if ($this->operator === 'ANY' || $this->operator === 'NONE') {
foreach($this->value as $value) {
//We cannnot use an paramater here, as this is the only way to pass the FCQN to the query (via binded params, we would need to use ClassMetaData). See: https://github.com/doctrine/orm/issues/4462
$expressions[] = ($queryBuilder->expr()->isInstanceOf($this->property, $value));
}
if($this->operator === 'ANY') {
$queryBuilder->andWhere($queryBuilder->expr()->orX(...$expressions));
} else { //NONE
$queryBuilder->andWhere($queryBuilder->expr()->not($queryBuilder->expr()->orX(...$expressions)));
}
} else {
throw new \RuntimeException('Unknown operator '. $this->operator . ' provided. Valid operators are '. implode(', ', self::ALLOWED_OPERATOR_VALUES));
}
}
}