mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-06-24 10:49:00 +02:00
Allow to filter parameters based on their text value
This commit is contained in:
parent
9ed953d1b2
commit
bc0365fe16
4 changed files with 78 additions and 10 deletions
|
@ -3,8 +3,10 @@
|
||||||
namespace App\DataTables\Filters\Constraints\Part;
|
namespace App\DataTables\Filters\Constraints\Part;
|
||||||
|
|
||||||
use App\DataTables\Filters\Constraints\AbstractConstraint;
|
use App\DataTables\Filters\Constraints\AbstractConstraint;
|
||||||
|
use App\DataTables\Filters\Constraints\TextConstraint;
|
||||||
use App\Entity\Parameters\PartParameter;
|
use App\Entity\Parameters\PartParameter;
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
|
use Svg\Tag\Text;
|
||||||
|
|
||||||
class ParameterConstraint extends AbstractConstraint
|
class ParameterConstraint extends AbstractConstraint
|
||||||
{
|
{
|
||||||
|
@ -17,9 +19,20 @@ class ParameterConstraint extends AbstractConstraint
|
||||||
/** @var string */
|
/** @var string */
|
||||||
protected $unit;
|
protected $unit;
|
||||||
|
|
||||||
|
/** @var TextConstraint */
|
||||||
|
protected $value_text;
|
||||||
|
|
||||||
|
/** @var string The alias to use for the subquery */
|
||||||
|
protected $alias;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
parent::__construct("parts.parameters");
|
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
|
public function isEnabled(): bool
|
||||||
|
@ -32,31 +45,39 @@ class ParameterConstraint extends AbstractConstraint
|
||||||
//Create a new qb to build the subquery
|
//Create a new qb to build the subquery
|
||||||
$subqb = new QueryBuilder($queryBuilder->getEntityManager());
|
$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)
|
$subqb->select('COUNT(' . $this->alias . ')')
|
||||||
->where($alias . '.element = part');
|
->from(PartParameter::class, $this->alias)
|
||||||
|
->where($this->alias . '.element = part');
|
||||||
|
|
||||||
if (!empty($this->name)) {
|
if (!empty($this->name)) {
|
||||||
$paramName = $this->generateParameterIdentifier('params.name');
|
$paramName = $this->generateParameterIdentifier('params.name');
|
||||||
$subqb->andWhere($alias . '.name = :' . $paramName);
|
$subqb->andWhere($this->alias . '.name = :' . $paramName);
|
||||||
$queryBuilder->setParameter($paramName, $this->name);
|
$queryBuilder->setParameter($paramName, $this->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($this->symbol)) {
|
if (!empty($this->symbol)) {
|
||||||
$paramName = $this->generateParameterIdentifier('params.symbol');
|
$paramName = $this->generateParameterIdentifier('params.symbol');
|
||||||
$subqb->andWhere($alias . '.symbol = :' . $paramName);
|
$subqb->andWhere($this->alias . '.symbol = :' . $paramName);
|
||||||
$queryBuilder->setParameter($paramName, $this->symbol);
|
$queryBuilder->setParameter($paramName, $this->symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($this->unit)) {
|
if (!empty($this->unit)) {
|
||||||
$paramName = $this->generateParameterIdentifier('params.unit');
|
$paramName = $this->generateParameterIdentifier('params.unit');
|
||||||
$subqb->andWhere($alias . '.unit = :' . $paramName);
|
$subqb->andWhere($this->alias . '.unit = :' . $paramName);
|
||||||
$queryBuilder->setParameter($paramName, $this->unit);
|
$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');
|
$queryBuilder->andWhere('(' . $subqb->getDQL() . ') > 0');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,4 +134,24 @@ class ParameterConstraint extends AbstractConstraint
|
||||||
$this->unit = $unit;
|
$this->unit = $unit;
|
||||||
return $this;
|
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;
|
||||||
|
}*/
|
||||||
}
|
}
|
|
@ -8,6 +8,8 @@ use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\SearchType;
|
use Symfony\Component\Form\Extension\Core\Type\SearchType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\Form\FormEvent;
|
||||||
|
use Symfony\Component\Form\FormEvents;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
class ParameterConstraintType extends AbstractType
|
class ParameterConstraintType extends AbstractType
|
||||||
|
@ -17,6 +19,7 @@ class ParameterConstraintType extends AbstractType
|
||||||
$resolver->setDefaults([
|
$resolver->setDefaults([
|
||||||
'compound' => true,
|
'compound' => true,
|
||||||
'data_class' => ParameterConstraint::class,
|
'data_class' => ParameterConstraint::class,
|
||||||
|
'empty_data' => new ParameterConstraint(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +34,26 @@ class ParameterConstraintType extends AbstractType
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$builder->add('symbol', SearchType::class, [
|
$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());
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Form\Filters;
|
namespace App\Form\Filters;
|
||||||
|
|
||||||
|
use App\DataTables\Filters\Constraints\Part\ParameterConstraint;
|
||||||
use App\DataTables\Filters\PartFilter;
|
use App\DataTables\Filters\PartFilter;
|
||||||
use App\Entity\Attachments\AttachmentType;
|
use App\Entity\Attachments\AttachmentType;
|
||||||
use App\Entity\Parts\Category;
|
use App\Entity\Parts\Category;
|
||||||
|
@ -211,12 +212,16 @@ class PartFilterType extends AbstractType
|
||||||
'label' => 'part.filter.attachmentName',
|
'label' => 'part.filter.attachmentName',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$constraint_prototype = new ParameterConstraint();
|
||||||
|
|
||||||
$builder->add('parameters', CollectionType::class, [
|
$builder->add('parameters', CollectionType::class, [
|
||||||
'label' => 'parameter.label',
|
'label' => 'parameter.label',
|
||||||
'entry_type' => ParameterConstraintType::class,
|
'entry_type' => ParameterConstraintType::class,
|
||||||
'allow_delete' => true,
|
'allow_delete' => true,
|
||||||
'allow_add' => true,
|
'allow_add' => true,
|
||||||
'reindex_enable' => false,
|
'reindex_enable' => false,
|
||||||
|
'prototype_data' => $constraint_prototype,
|
||||||
|
'empty_data' => $constraint_prototype,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$builder->add('submit', SubmitType::class, [
|
$builder->add('submit', SubmitType::class, [
|
||||||
|
|
|
@ -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 {{ 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></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 {{ 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>
|
<td>
|
||||||
<button type="button" class="btn btn-danger btn-sm" {{ collection.delete_btn() }} title="{% trans %}orderdetail.delete{% endtrans %}">
|
<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>
|
<i class="fas fa-trash-alt fa-fw"></i>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue