Allow to filter by the number of part lots.

This commit is contained in:
Jan Böhmer 2022-08-28 19:39:16 +02:00
parent 99b25fb293
commit b8c77ca855
4 changed files with 63 additions and 3 deletions

View file

@ -7,6 +7,23 @@ use Doctrine\ORM\QueryBuilder;
trait FilterTrait trait FilterTrait
{ {
protected $useHaving = false;
public function useHaving($value = true): self
{
$this->useHaving = $value;
return $this;
}
/**
* Checks if the given input is an aggregateFunction like COUNT(part.partsLot) or so
* @return bool
*/
protected function isAggregateFunctionString(string $input): bool
{
return preg_match('/^[a-zA-Z]+\(.*\)$/', $input) === 1;
}
/** /**
* Generates a parameter identifier that can be used for the given property. It gives random results, to be unique, so you have to cache it. * Generates a parameter identifier that can be used for the given property. It gives random results, to be unique, so you have to cache it.
* @param string $property * @param string $property
@ -14,7 +31,10 @@ trait FilterTrait
*/ */
protected function generateParameterIdentifier(string $property): string protected function generateParameterIdentifier(string $property): string
{ {
return str_replace('.', '_', $property) . '_' . uniqid("", false); //Replace all special characters with underscores
$property = preg_replace('/[^a-zA-Z0-9_]/', '_', $property);
//Add a random number to the end of the property name for uniqueness
return $property . '_' . uniqid("", false);
} }
/** /**
@ -27,7 +47,12 @@ trait FilterTrait
*/ */
protected function addSimpleAndConstraint(QueryBuilder $queryBuilder, string $property, string $parameterIdentifier, string $comparison_operator, $value): void protected function addSimpleAndConstraint(QueryBuilder $queryBuilder, string $property, string $parameterIdentifier, string $comparison_operator, $value): void
{ {
$queryBuilder->andWhere(sprintf("%s %s (:%s)", $property, $comparison_operator, $parameterIdentifier)); if($this->useHaving || $this->isAggregateFunctionString($property)) { //If the property is an aggregate function, we have to use the "having" instead of the "where"
$queryBuilder->andHaving(sprintf("%s %s (:%s)", $property, $comparison_operator, $parameterIdentifier));
} else {
$queryBuilder->andWhere(sprintf("%s %s (:%s)", $property, $comparison_operator, $parameterIdentifier));
}
$queryBuilder->setParameter($parameterIdentifier, $value); $queryBuilder->setParameter($parameterIdentifier, $value);
} }
} }

View file

@ -0,0 +1,20 @@
<?php
namespace App\DataTables\Filters\Constraints;
use Doctrine\ORM\QueryBuilder;
class IntConstraint extends NumberConstraint
{
public function apply(QueryBuilder $queryBuilder): void
{
if($this->value1 !== null) {
$this->value1 = (int) $this->value1;
}
if($this->value2 !== null) {
$this->value2 = (int) $this->value2;
}
parent::apply($queryBuilder);
}
}

View file

@ -5,6 +5,7 @@ namespace App\DataTables\Filters;
use App\DataTables\Filters\Constraints\BooleanConstraint; use App\DataTables\Filters\Constraints\BooleanConstraint;
use App\DataTables\Filters\Constraints\DateTimeConstraint; use App\DataTables\Filters\Constraints\DateTimeConstraint;
use App\DataTables\Filters\Constraints\EntityConstraint; use App\DataTables\Filters\Constraints\EntityConstraint;
use App\DataTables\Filters\Constraints\IntConstraint;
use App\DataTables\Filters\Constraints\NumberConstraint; use App\DataTables\Filters\Constraints\NumberConstraint;
use App\DataTables\Filters\Constraints\Part\TagsConstraint; use App\DataTables\Filters\Constraints\Part\TagsConstraint;
use App\DataTables\Filters\Constraints\TextConstraint; use App\DataTables\Filters\Constraints\TextConstraint;
@ -70,6 +71,9 @@ class PartFilter implements FilterInterface
/** @var EntityConstraint */ /** @var EntityConstraint */
protected $storelocation; protected $storelocation;
/** @var NumberConstraint */
protected $lotCount;
/** @var EntityConstraint */ /** @var EntityConstraint */
protected $measurementUnit; protected $measurementUnit;
@ -92,7 +96,7 @@ class PartFilter implements FilterInterface
$this->needsReview = new BooleanConstraint('part.needs_review'); $this->needsReview = new BooleanConstraint('part.needs_review');
$this->measurementUnit = new EntityConstraint($nodesListBuilder, MeasurementUnit::class, 'part.partUnit'); $this->measurementUnit = new EntityConstraint($nodesListBuilder, MeasurementUnit::class, 'part.partUnit');
$this->mass = new NumberConstraint('part.mass'); $this->mass = new NumberConstraint('part.mass');
$this->dbId = new NumberConstraint('part.id'); $this->dbId = new IntConstraint('part.id');
$this->addedDate = new DateTimeConstraint('part.addedDate'); $this->addedDate = new DateTimeConstraint('part.addedDate');
$this->lastModified = new DateTimeConstraint('part.lastModified'); $this->lastModified = new DateTimeConstraint('part.lastModified');
@ -104,6 +108,7 @@ class PartFilter implements FilterInterface
$this->manufacturer_product_url = new TextConstraint('part.manufacturer_product_url'); $this->manufacturer_product_url = new TextConstraint('part.manufacturer_product_url');
$this->storelocation = new EntityConstraint($nodesListBuilder, Storelocation::class, 'partLots.storage_location'); $this->storelocation = new EntityConstraint($nodesListBuilder, Storelocation::class, 'partLots.storage_location');
$this->lotCount = new IntConstraint('COUNT(partLots)');
} }
public function apply(QueryBuilder $queryBuilder): void public function apply(QueryBuilder $queryBuilder): void
@ -244,6 +249,11 @@ class PartFilter implements FilterInterface
return $this->manufacturer_product_number; return $this->manufacturer_product_number;
} }
public function getLotCount(): NumberConstraint
{
return $this->lotCount;
}
/** /**
* @return TagsConstraint * @return TagsConstraint
*/ */

View file

@ -142,6 +142,11 @@ class PartFilterType extends AbstractType
'min' => 0, 'min' => 0,
]); ]);
$builder->add('lotCount', NumberConstraintType::class, [
'label' => 'part.filter.lot_count',
'min' => 0
]);
$builder->add('submit', SubmitType::class, [ $builder->add('submit', SubmitType::class, [
'label' => 'Update', 'label' => 'Update',