Allow to filter parameters based on their text value

This commit is contained in:
Jan Böhmer 2022-09-07 21:43:01 +02:00
parent 9ed953d1b2
commit bc0365fe16
4 changed files with 78 additions and 10 deletions

View file

@ -3,8 +3,10 @@
namespace App\DataTables\Filters\Constraints\Part;
use App\DataTables\Filters\Constraints\AbstractConstraint;
use App\DataTables\Filters\Constraints\TextConstraint;
use App\Entity\Parameters\PartParameter;
use Doctrine\ORM\QueryBuilder;
use Svg\Tag\Text;
class ParameterConstraint extends AbstractConstraint
{
@ -17,9 +19,20 @@ class ParameterConstraint extends AbstractConstraint
/** @var string */
protected $unit;
/** @var TextConstraint */
protected $value_text;
/** @var string The alias to use for the subquery */
protected $alias;
public function __construct()
{
parent::__construct("parts.parameters");
//The alias has to be uniq for each subquery, so generate a random one
$this->alias = uniqid('param_', false);
$this->value_text = new TextConstraint($this->alias . '.value_text');
}
public function isEnabled(): bool
@ -32,31 +45,39 @@ class ParameterConstraint extends AbstractConstraint
//Create a new qb to build the subquery
$subqb = new QueryBuilder($queryBuilder->getEntityManager());
//The alias has to be uniq for each subquery, so generate a random one
$alias = uniqid('param_', false);
$subqb->select('COUNT(' . $alias . ')')
->from(PartParameter::class, $alias)
->where($alias . '.element = part');
$subqb->select('COUNT(' . $this->alias . ')')
->from(PartParameter::class, $this->alias)
->where($this->alias . '.element = part');
if (!empty($this->name)) {
$paramName = $this->generateParameterIdentifier('params.name');
$subqb->andWhere($alias . '.name = :' . $paramName);
$subqb->andWhere($this->alias . '.name = :' . $paramName);
$queryBuilder->setParameter($paramName, $this->name);
}
if (!empty($this->symbol)) {
$paramName = $this->generateParameterIdentifier('params.symbol');
$subqb->andWhere($alias . '.symbol = :' . $paramName);
$subqb->andWhere($this->alias . '.symbol = :' . $paramName);
$queryBuilder->setParameter($paramName, $this->symbol);
}
if (!empty($this->unit)) {
$paramName = $this->generateParameterIdentifier('params.unit');
$subqb->andWhere($alias . '.unit = :' . $paramName);
$subqb->andWhere($this->alias . '.unit = :' . $paramName);
$queryBuilder->setParameter($paramName, $this->unit);
}
//Apply all subfilters
$this->value_text->apply($subqb);
//Copy all parameters from the subquery to the main query
//We can not use setParameters here, as this would override the exiting paramaters in queryBuilder
foreach ($subqb->getParameters() as $parameter) {
$queryBuilder->setParameter($parameter->getName(), $parameter->getValue());
}
$queryBuilder->andWhere('(' . $subqb->getDQL() . ') > 0');
}
@ -113,4 +134,24 @@ class ParameterConstraint extends AbstractConstraint
$this->unit = $unit;
return $this;
}
/**
* @return TextConstraint
*/
public function getValueText(): TextConstraint
{
return $this->value_text;
}
/**
* DO NOT USE THIS SETTER!
* This is just a workaround for collectionType behavior
* @param $value
* @return $this
*/
/*public function setValueText($value): self
{
//Do not really set the value here, as we dont want to override the constraint created in the constructor
return $this;
}*/
}

View file

@ -8,6 +8,8 @@ use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\SearchType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ParameterConstraintType extends AbstractType
@ -17,6 +19,7 @@ class ParameterConstraintType extends AbstractType
$resolver->setDefaults([
'compound' => true,
'data_class' => ParameterConstraint::class,
'empty_data' => new ParameterConstraint(),
]);
}
@ -33,5 +36,24 @@ class ParameterConstraintType extends AbstractType
$builder->add('symbol', SearchType::class, [
'required' => false
]);
$builder->add('value_text', TextConstraintType::class, [
//'required' => false,
] );
/*
* I am not quite sure why this is needed, but somehow symfony tries to create a new instance of TextConstraint
* instead of using the existing one for the prototype (or the one from empty data). This fails as the constructor of TextConstraint requires
* arguments.
* Ensure that the data is never null, but use an empty ParameterConstraint instead
*/
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$form = $event->getForm();
$data = $event->getData();
if ($data === null) {
$event->setData(new ParameterConstraint());
}
});
}
}

View file

@ -2,6 +2,7 @@
namespace App\Form\Filters;
use App\DataTables\Filters\Constraints\Part\ParameterConstraint;
use App\DataTables\Filters\PartFilter;
use App\Entity\Attachments\AttachmentType;
use App\Entity\Parts\Category;
@ -211,12 +212,16 @@ class PartFilterType extends AbstractType
'label' => 'part.filter.attachmentName',
]);
$constraint_prototype = new ParameterConstraint();
$builder->add('parameters', CollectionType::class, [
'label' => 'parameter.label',
'entry_type' => ParameterConstraintType::class,
'allow_delete' => true,
'allow_add' => true,
'reindex_enable' => false,
'prototype_data' => $constraint_prototype,
'empty_data' => $constraint_prototype,
]);
$builder->add('submit', SubmitType::class, [

View file

@ -47,7 +47,7 @@
<td {{ stimulus_controller('pages/latex_preview') }}>{{ form_widget(form.symbol, {"attr": {"data-pages--parameters-autocomplete-target": "symbol", "data-pages--latex-preview-target": "input"}}) }}<span {{ stimulus_target('pages/latex_preview', 'preview') }}></span></td>
<td></td>
<td {{ stimulus_controller('pages/latex_preview') }}>{{ form_widget(form.unit, {"attr": {"data-pages--parameters-autocomplete-target": "unit", "data-pages--latex-preview-target": "input"}}) }}<span {{ stimulus_target('pages/latex_preview', 'preview') }}></span></td>
<td></td>
<td>{{ form_widget(form.value_text) }}</td>
<td>
<button type="button" class="btn btn-danger btn-sm" {{ collection.delete_btn() }} title="{% trans %}orderdetail.delete{% endtrans %}">
<i class="fas fa-trash-alt fa-fw"></i>