Implement a filter for Log Table (part 1)

This commit is contained in:
Jan Böhmer 2022-09-11 18:45:31 +02:00
parent 017b0f717e
commit c7f5c23374
12 changed files with 444 additions and 23 deletions

View file

@ -6,6 +6,7 @@ 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\IntConstraint;
use App\DataTables\Filters\Constraints\NumberConstraint;
use App\DataTables\Filters\Constraints\TextConstraint;
use App\Entity\Attachments\AttachmentType;
@ -40,7 +41,7 @@ class AttachmentFilter implements FilterInterface
public function __construct(NodesListBuilder $nodesListBuilder)
{
$this->dbId = new NumberConstraint('attachment.id');
$this->dbId = new IntConstraint('attachment.id');
$this->name = new TextConstraint('attachment.name');
$this->targetType = new InstanceOfConstraint('attachment');
$this->attachmentType = new EntityConstraint($nodesListBuilder, AttachmentType::class, 'attachment.attachment_type');

View file

@ -9,7 +9,7 @@ class ChoiceConstraint extends AbstractConstraint
public const ALLOWED_OPERATOR_VALUES = ['ANY', 'NONE'];
/**
* @var string[] The values to compare to
* @var string[]|int[] The values to compare to
*/
protected $value;
@ -19,7 +19,7 @@ class ChoiceConstraint extends AbstractConstraint
protected $operator;
/**
* @return string[]
* @return string[]|int[]
*/
public function getValue(): array
{
@ -27,7 +27,7 @@ class ChoiceConstraint extends AbstractConstraint
}
/**
* @param string[] $value
* @param string[]|int[] $value
* @return ChoiceConstraint
*/
public function setValue(array $value): ChoiceConstraint

View file

@ -36,18 +36,22 @@ class EntityConstraint extends AbstractConstraint
protected $value;
/**
* @param NodesListBuilder $nodesListBuilder
* @param class-string<T> $class
* @param NodesListBuilder|null $nodesListBuilder
* @param class-string $class
* @param string $property
* @param string|null $identifier
* @param $value
* @param string $operator
* @param null $value
* @param string $operator
*/
public function __construct(NodesListBuilder $nodesListBuilder, string $class, string $property, string $identifier = null, $value = null, string $operator = '')
public function __construct(?NodesListBuilder $nodesListBuilder, string $class, string $property, string $identifier = null, $value = null, string $operator = '')
{
$this->nodesListBuilder = $nodesListBuilder;
$this->class = $class;
if ($nodesListBuilder === null && $this->isStructural()) {
throw new \InvalidArgumentException('NodesListBuilder must be provided for structural entities');
}
parent::__construct($property, $identifier);
$this->value = $value;
$this->operator = $operator;

View file

@ -0,0 +1,110 @@
<?php
namespace App\DataTables\Filters;
use App\DataTables\Filters\Constraints\ChoiceConstraint;
use App\DataTables\Filters\Constraints\DateTimeConstraint;
use App\DataTables\Filters\Constraints\EntityConstraint;
use App\DataTables\Filters\Constraints\InstanceOfConstraint;
use App\DataTables\Filters\Constraints\IntConstraint;
use App\DataTables\Filters\Constraints\NumberConstraint;
use App\Entity\UserSystem\User;
use Doctrine\ORM\QueryBuilder;
class LogFilter implements FilterInterface
{
use CompoundFilterTrait;
/** @var DateTimeConstraint */
protected $timestamp;
/** @var IntConstraint */
protected $dbId;
/** @var ChoiceConstraint */
protected $level;
/** @var InstanceOfConstraint */
protected $eventType;
/** @var ChoiceConstraint */
protected $targetType;
/** @var IntConstraint */
protected $targetId;
/** @var EntityConstraint */
protected $user;
public function __construct()
{
$this->timestamp = new DateTimeConstraint('log.timestamp');
$this->dbId = new IntConstraint('log.id');
$this->level = new ChoiceConstraint('log.level');
$this->eventType = new InstanceOfConstraint('log');
$this->user = new EntityConstraint(null, User::class, 'log.user');
$this->targetType = new ChoiceConstraint('log.target_type');
$this->targetId = new IntConstraint('log.target_id');
}
public function apply(QueryBuilder $queryBuilder): void
{
$this->applyAllChildFilters($queryBuilder);
}
/**
* @return DateTimeConstraint
*/
public function getTimestamp(): DateTimeConstraint
{
return $this->timestamp;
}
/**
* @return IntConstraint|NumberConstraint
*/
public function getDbId()
{
return $this->dbId;
}
/**
* @return ChoiceConstraint
*/
public function getLevel(): ChoiceConstraint
{
return $this->level;
}
/**
* @return InstanceOfConstraint
*/
public function getEventType(): InstanceOfConstraint
{
return $this->eventType;
}
/**
* @return ChoiceConstraint
*/
public function getTargetType(): ChoiceConstraint
{
return $this->targetType;
}
/**
* @return IntConstraint
*/
public function getTargetId(): IntConstraint
{
return $this->targetId;
}
public function getUser(): EntityConstraint
{
return $this->user;
}
}

View file

@ -47,6 +47,8 @@ use App\DataTables\Column\LocaleDateTimeColumn;
use App\DataTables\Column\LogEntryExtraColumn;
use App\DataTables\Column\LogEntryTargetColumn;
use App\DataTables\Column\RevertLogColumn;
use App\DataTables\Filters\AttachmentFilter;
use App\DataTables\Filters\LogFilter;
use App\Entity\Base\AbstractDBElement;
use App\Entity\Contracts\TimeTravelInterface;
use App\Entity\LogSystem\AbstractLogEntry;
@ -61,6 +63,7 @@ use App\Services\ElementTypeNameGenerator;
use App\Services\EntityURLGenerator;
use Doctrine\ORM\EntityManagerInterface;
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;
@ -97,10 +100,12 @@ class LogDataTable implements DataTableTypeInterface
$optionsResolver->setDefaults([
'mode' => 'system_log',
'filter_elements' => [],
'filter' => null,
]);
$optionsResolver->setAllowedTypes('filter_elements', ['array', 'object']);
$optionsResolver->setAllowedTypes('mode', 'string');
$optionsResolver->setAllowedTypes('filter', LogFilter::class);
$optionsResolver->setNormalizer('filter_elements', static function (Options $options, $value) {
if (!is_array($value)) {
@ -192,8 +197,8 @@ class LogDataTable implements DataTableTypeInterface
'label' => $this->translator->trans('log.level'),
'visible' => 'system_log' === $options['mode'],
'propertyPath' => 'levelString',
'render' => static function (string $value, AbstractLogEntry $context) {
return $value;
'render' => function (string $value, AbstractLogEntry $context) {
return $this->translator->trans('log.level.'.$value);
},
]);
@ -271,9 +276,24 @@ class LogDataTable implements DataTableTypeInterface
'query' => function (QueryBuilder $builder) use ($options): void {
$this->getQuery($builder, $options);
},
'criteria' => [
function (QueryBuilder $builder) use ($options): void {
$this->buildCriteria($builder, $options);
},
new SearchCriteriaProvider(),
],
]);
}
private function buildCriteria(QueryBuilder $builder, array $options): void
{
if (!empty($options['filter'])) {
$filter = $options['filter'];
$filter->apply($builder);
}
}
protected function getQuery(QueryBuilder $builder, array $options): void
{
$builder->distinct()->select('log')
@ -281,6 +301,7 @@ class LogDataTable implements DataTableTypeInterface
->from(AbstractLogEntry::class, 'log')
->leftJoin('log.user', 'user');
/* Do this here as we don't want to show up the global count of all log entries in the footer line, with these modes */
if ('last_activity' === $options['mode']) {
$builder->where('log INSTANCE OF '.ElementCreatedLogEntry::class)
->orWhere('log INSTANCE OF '.ElementDeletedLogEntry::class)