diff --git a/src/DataTables/Filters/Constraints/Part/ParameterConstraint.php b/src/DataTables/Filters/Constraints/Part/ParameterConstraint.php index 318cc3d4..288eff88 100644 --- a/src/DataTables/Filters/Constraints/Part/ParameterConstraint.php +++ b/src/DataTables/Filters/Constraints/Part/ParameterConstraint.php @@ -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; + }*/ } \ No newline at end of file diff --git a/src/Form/Filters/Constraints/ParameterConstraintType.php b/src/Form/Filters/Constraints/ParameterConstraintType.php index 39a2ca9e..f5596bfe 100644 --- a/src/Form/Filters/Constraints/ParameterConstraintType.php +++ b/src/Form/Filters/Constraints/ParameterConstraintType.php @@ -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(), ]); } @@ -31,7 +34,26 @@ class ParameterConstraintType extends AbstractType ]); $builder->add('symbol', SearchType::class, [ - 'required' => false + '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()); + } + }); } } \ No newline at end of file diff --git a/src/Form/Filters/PartFilterType.php b/src/Form/Filters/PartFilterType.php index 0583715e..84d3137f 100644 --- a/src/Form/Filters/PartFilterType.php +++ b/src/Form/Filters/PartFilterType.php @@ -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, [ diff --git a/templates/Form/FilterTypesLayout.html.twig b/templates/Form/FilterTypesLayout.html.twig index a84ca51e..55292570 100644 --- a/templates/Form/FilterTypesLayout.html.twig +++ b/templates/Form/FilterTypesLayout.html.twig @@ -47,7 +47,7 @@ {{ form_widget(form.symbol, {"attr": {"data-pages--parameters-autocomplete-target": "symbol", "data-pages--latex-preview-target": "input"}}) }} {{ form_widget(form.unit, {"attr": {"data-pages--parameters-autocomplete-target": "unit", "data-pages--latex-preview-target": "input"}}) }} - + {{ form_widget(form.value_text) }}