### Install FormFilterBundle via Composer Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/installation.md Use this command to add the bundle to your project dependencies. ```bash composer require spiriitlabs/form-filter-bundle ``` -------------------------------- ### Implementing the CRUD List Component Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/advanced-usage-with-pagerfanta-bundle.md Usage example of the crud-list component, overriding blocks to define specific filter fields and table columns. ```html {% block body %} {% component 'crud-list' with { pager: pager, form: form, } %} {% block formFilterRows %}
{{ form_widget(form.name) }}
{{ form_widget(form.email) }}
{% endblock %} {% block tableTh %} name email {% endblock %} {% block tableTd %} {# @var object \My\Folder\Object #} {{ object.name }} {{ object.email }} {% endblock %} {% block tableEdit %} edit {% endblock %} {% endcomponent %} {% endblock %} ``` -------------------------------- ### Configure FilterType for GET requests Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/working-with-the-bundle.md Set form options to ensure proper validation and method handling for filter forms. ```php public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'error_bubbling' => true, 'csrf_protection' => false, 'validation_groups' => ['filtering'], // avoid NotBlank() constraint-related message 'method' => 'get', ]); } ``` -------------------------------- ### Filter Type Event Registration Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/basics.md Example of adding a filter field within a form builder to trigger event-based condition application. ```php use Spiriit\Bundle\FormFilterBundle\Filter\Form\Type as Filters; public function buildForm(FormBuilder $builder, array $options) { $builder->add('name', Filters\TextFilterType::class); } ``` -------------------------------- ### Integrate KNP Paginator with FilterBuilder Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/working-with-other-bundles.md Demonstrates how to apply filter conditions to a query builder before passing it to the KNP Paginator service. ```php myRepository ->createQueryBuilder('e'); $form = $this->formFactory->create(new ItemFilterType()); if ($request->query->has($form->getName())) { // manually bind values from the request $form->submit($request->query->get($form->getName())); // build the query from the given form object $this->filterBuilderUpdater->addFilterConditions($form, $filterBuilder); } $query = $filterBuilder->getQuery(); $paginator = $this->get('knp_paginator'); $pagination = $paginator->paginate( $query, $request->query->get('page', 1)/*page number*/, 10/*limit per page*/ ); return $this->render('ProjectSuperBundle:Default:testFilter.html.twig', array( 'form' => $form->createView(), 'pagination' => $pagination )); } } ``` -------------------------------- ### Update Namespace Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/UPGRADE-9.0.md Replace the old Lexik namespace with the new Spiriit namespace throughout the codebase. ```php Lexik\Bundle\FormFilterBundle ``` ```php Spiriit\Bundle\FormFilterBundle ``` -------------------------------- ### Configure bundle listeners Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/configuration.md Enable or disable specific query builder listeners in the bundle configuration. ```yaml # config/packages/spiriit_form_filter.yaml spiriit_form_filter: listeners: doctrine_orm: true ``` -------------------------------- ### Create Helper Class for Pagination Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/advanced-usage-with-pagerfanta-bundle.md Define a helper class to manage QueryBuilder operations, filtering, and Pagerfanta instantiation. ```php // your helper class public function getAllQb(): QueryBuilder { return $this->createQueryBuilder($this->getAlias()); } public function paginateWithFilters( ListOptions $options, FormInterface $form = null, QueryBuilder $qb = null, ): Pagerfanta { try { $sorting = $options->get('sorting'); if (!\is_array($sorting)) { throw new \RuntimeException('need array'); } } catch (\RuntimeException $e) { $sorting = []; } if (null === $form) { $queryBuilder = $qb ?? $this->getCollectionQueryBuilder(); if (!empty($sorting)) { $this->applySorting($queryBuilder, $sorting); } return $this->paginate($options, $queryBuilder); } return $this->paginate( $options, $this->getFilteredResource($form, $sorting, $qb), ); } public function getPager(QueryBuilder $qb, int $page = 1, int $maxPerPage = 10): Pagerfanta { $pager = new Pagerfanta(new QueryAdapter($qb)); $pager->setMaxPerPage($maxPerPage); $pager->setCurrentPage($page); return $pager; } public function paginate(ListOptions $options, QueryBuilder $queryBuilder = null): Pagerfanta { if (null === $queryBuilder) { $queryBuilder = $this->getAllQb(); } try { $page = $options->get('page'); $limit = $options->get('limit'); if (!\is_int($page) || !\is_int($limit)) { throw new \RuntimeException('int parameter'); } } catch (\RuntimeException $e) { $page = 1; $limit = 10; } return $this->getPager( $queryBuilder, $page, $limit, ); } public function getFilteredResource( FormInterface $form, ?array $sorting = [], QueryBuilder $qb = null, ): QueryBuilder { $queryBuilder = $qb ?? $this->getCollectionQueryBuilder(); $this->applyFilters($form, $queryBuilder); if (!empty($sorting)) { $this->applySorting($queryBuilder, $sorting); } return $queryBuilder; } protected function getPropertyName(string $name): string { if (!str_contains($name, '.')) { return $this->getAlias().'.'.$name; } return $name; } protected function applySorting(QueryBuilder $queryBuilder, array $sorting = []): void { foreach ($sorting as $property => $order) { if (!empty($order)) { $queryBuilder->addOrderBy($this->getPropertyName($property), $order); } } } protected function getAlias(): string { return 'o'; } protected function applyFilters(FormInterface $form, QueryBuilder $queryBuilder): void { if (null === $form->getData()) { return; } $this->filterBuilderUpdater->addFilterConditions($form, $queryBuilder); } ``` -------------------------------- ### Update bundles.php Configuration Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/UPGRADE-9.0.md Update the bundle registration in bundles.php to reflect the new namespace and class name. ```php use Lexik\Bundle\FormFilterBundle\LexikFormFilterBundle; ... LexikFormFilterBundle::class => ['all' => true], ``` ```php use Spiriit\Bundle\FormFilterBundle\SpiriitFormFilterBundle; ... SpiriitFormFilterBundle::class => ['all' => true], ``` -------------------------------- ### Alternative event subscription for standard types Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/working-with-the-bundle.md Listen to standard locale events when using the default data extraction method. ```php [...] class FilterSubscriber implements EventSubscriberInterface { /** * {@inheritDoc} */ public static function getSubscribedEvents() { return [ 'spiriit_form_filter.apply.orm.locale' => ['filterLocale'], 'spiriit_form_filter.apply.dbal.locale' => ['filterLocale'], ]; } [...] } ``` -------------------------------- ### Implementing a Custom Data Extraction Method Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/filtertypeextension.md Define a custom extraction method by implementing DataExtractionMethodInterface and registering it as a service with the appropriate tag. ```php $form->getData(), // The value used to filter, most time the form value. ]; // add other stuff into $values return $values; } } ``` ```xml ``` ```php use Spiriit\Bundle\FormFilterBundle\Filter\Form\Type as Filters; public function buildForm(FormBuilderInterface $builder, array $options) { $builder->add('my_text_field', Filters\TextFilterType::class, array( 'data_extraction_method' => 'rainbow', )); } ``` -------------------------------- ### Implement a FilterSubscriber Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/working-with-the-bundle.md Create an event subscriber to handle filter conditions for both ORM and DBAL query builders. ```php namespace Super\Namespace\Listener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Spiriit\Bundle\FormFilterBundle\Event\GetFilterConditionEvent; class FilterSubscriber implements EventSubscriberInterface { /** * {@inheritDoc} */ public static function getSubscribedEvents(): array { return [ // if a Doctrine\ORM\QueryBuilder is passed to the spiriit_form_filter.query_builder_updater service // "locale_filter" is the block prefix of the LocaleFilterType 'spiriit_form_filter.apply.orm.locale_filter' => ['filterLocale'], // if a Doctrine\DBAL\Query\QueryBuilder is passed to the spiriit_form_filter.query_builder_updater service // "locale_filter" is the block prefix of the LocaleFilterType 'spiriit_form_filter.apply.dbal.locale_filter' => ['filterLocale'], ]; } /** * Apply a filter for a LocaleFilterType type. * * This method should work with both ORM and DBAL query builder. */ public function filterLocale(GetFilterConditionEvent $event): void { $expr = $event->getFilterQuery()->getExpr(); $values = $event->getValues(); if ('' !== $values['value'] && null !== $values['value']) { $paramName = str_replace('.', '_', $event->getField()); $event->setCondition( $expr->eq($event->getField(), ':'.$paramName), [$paramName => $values['value']] ); } } } ``` -------------------------------- ### Update Bundle Configuration Key Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/UPGRADE-9.0.md Update the configuration file key from lexik_form_filter to spiriit_form_filter. ```yaml lexik_form_filter ``` ```yaml spiriit_form_filter ``` -------------------------------- ### Implement Pagerfanta in Controller Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/advanced-usage-with-pagerfanta-bundle.md Use the helper class to paginate filtered results within a Symfony controller. ```php // your controller public function __invoke(Request $request): Response { $form = $this->createForm(FilterType::class, null, [ 'method' => Request::METHOD_GET, ]); $form->handleRequest($request); $pager = $this->helperClass->paginateWithFilters( new ListOptions([ 'page' => $request->query->get('page', '1'), 'limit' => $request->query->get('per_page', '20'), 'sorting' => ['date' => 'ASC'], ]), $form, $this->getQueryBuilder(), ); return $this->render('demo/test.html.twig', [ 'pager' => $pager, 'form' => $form, ]); } ``` -------------------------------- ### Configure case insensitivity Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/configuration.md Adjust case sensitivity settings for LIKE comparisons, particularly for Postgres databases. ```yaml # config/packages/spiriit_form_filter.yaml spiriit_form_filter: force_case_insensitivity: false encoding: ~ # Encoding for case insensitive LIKE comparisons. For example: UTF-8 ``` -------------------------------- ### Configure global text filter pattern Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/configuration.md Set the default text pattern used by the TextFilterType globally. ```yaml # config/packages/spiriit_form_filter.yaml spiriit_form_filter: condition_pattern: text.starts ``` -------------------------------- ### Configure Twig form themes Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/configuration.md Register the bundle's template blocks in your Twig configuration. ```yaml # config/packages/twig.yaml twig: form_themes: - '@SpiriitFormFilter/Form/form_div_layout.html.twig' ``` -------------------------------- ### Integrate PagerFanta with FilterBuilder Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/working-with-other-bundles.md Shows the implementation of filtering logic within a controller using PagerFanta for pagination. ```php formFactory->create(new ItemFilterType()); if ($request->query->has($form->getName())) { // manually bind values from the request $form->submit($request->query->get($form->getName())); // build the query from the given form object $this->filterBuilderUpdater->addFilterConditions($form, $filterBuilder); } $query = $filterBuilder->getQuery(); $pager = $this->paginateWithFilters( new ListOptions([ 'page' => $request->query->get('page', '1'), 'limit' => $request->query->get('per_page', '100'), 'sorting' => $request->query->get('sorting') ?? [ 'status' => 'ASC', ], ]), $form, $this->myRepository->getAllQueryBuilder(), ); return $this->render('ProjectSuperBundle:Default:testFilter.html.twig', array( 'form' => $form->createView(), 'pager' => $pager )); } } ``` -------------------------------- ### Define a Doctrine Entity Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/basics.md Create a standard Doctrine ORM entity to be used with the filter bundle. ```php add('item', ItemFilterType::class, array( 'add_shared' => function (FilterBuilderExecuterInterface $qbe) { $closure = function (QueryBuilder $filterBuilder, $alias, $joinAlias, Expr $expr) { $filterBuilder->leftJoin($alias . '.item', $joinAlias); }; $qbe->addOnce($qbe->getAlias().'.item', 'i', $closure); } )); } } ``` -------------------------------- ### Customizing Filter Application with apply_filter Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/filtertypeextension.md Use the apply_filter option to override default filtering logic using a callback or Closure. ```php add('my_text_field', Filters\TextFilterType::class, [ 'apply_filter' => [$this, 'textFieldCallback'], ]); $builder->add('my_number_field', Filters\NumberFilterType::class, [ 'apply_filter' => function(QueryInterface $filterQuery, $field, $values) { if (empty($values['value'])) { return null; } $expr = $filterQuery->getExpr(); $paramName = sprintf('p_%s', str_replace('.', '_', $field)); return $filterQuery->createCondition( $expr->eq($field, ':' . $paramName), // expression [$paramName => $values['value']] // parameters [ name => value ] ); }, ]); } public function getBlockPrefix() { return 'item_filter'; } public function textFieldCallback(QueryInterface $filterQuery, $field, $values) { if (empty($values['value'])) { return null; } $expr = $filterQuery->getExpr(); $paramName = sprintf('p_%s', str_replace('.', '_', $field)); return $filterQuery->createCondition( $expr->eq($field, ':'.$paramName), // expression [$paramName => [$values['value'], \PDO::PARAM_STR]] // parameters [ name => [value, type] ] ); } } ``` -------------------------------- ### Configure filter condition builder Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/working-with-the-bundle.md Implementation of the filter_condition_builder option to define complex logical relationships between filter fields. ```php add('name', Filters TextFilterType::class); $builder->add('date', Filters NumberFilterType::class); $builder->add('options', new RelatedOptionsType()); } public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults(array( 'filter_condition_builder' => function (ConditionBuilderInterface $builder) { $builder ->root('or') ->field('options.label') ->andX() ->field('options.rank') ->field('name') ->end() ->field('date') ->end() ; } )); } } ``` ```php $resolver->setDefaults(array( 'filter_condition_builder' => function (ConditionBuilderInterface $builder) { $builder ->root('and') ->orX() ->field('options.label') ->field('name') ->end() ->orX() ->field('options.rank') ->field('date') ->end() ->end() ; } )); ``` -------------------------------- ### Implement Filtering in Controller Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/basics.md Bind the filter form to the request and use FilterBuilderUpdater to apply conditions to the QueryBuilder. ```php create(ItemFilterType::class); // manually bind values from the request $form->submit($request->query->get($form->getName())); // initialize a query builder $filterBuilder = $em ->getRepository(MyEntity::class) ->createQueryBuilder('e'); // build the query from the given form object $filterBuilderUpdater->addFilterConditions($form, $filterBuilder); // now look at the DQL =) dump($filterBuilder->getDql()); return $this->render('testFilter.html.twig', [ 'form' => $form, ]); } } ``` -------------------------------- ### Create a custom LocaleFilterType Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/working-with-the-bundle.md Define a custom filter type by extending AbstractType and setting the parent to LocaleType. ```php namespace Super\Namespace\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Form\Extension\Core\Type\LocaleType; class LocaleFilterType extends AbstractType { public function configureOptions(OptionsResolver $resolver) { $resolver ->setDefaults([ 'data_extraction_method' => 'default', ]) ->setAllowedValues('data_extraction_method', ['default']) ; } public function getParent() { return LocaleType::class; } } ``` -------------------------------- ### Use existing join aliases with QueryBuilderUpdater Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/working-with-the-bundle.md Pre-define join aliases using setParts to reuse existing joins on the QueryBuilder before applying filter conditions. ```php $form = /* your form filter instance */; $queryBuilder = $em ->getRepository(MyEntity::class) ->createQueryBuilder('e'); $queryBuilder ->select('e, u, a') ->leftJoin('e.user', 'u') ->innerJoin('u.addresses', 'a'); $queryBuilderUpdater = // inject FilterBuilderUpdater::class // set the joins $qbUpdater->setParts(array( '__root__' => 'e', 'e.user' => 'u', 'u.addresses' => 'a', )); // then add filter conditions $queryBuilderUpdater->addFilterConditions($form, $queryBuilder); ``` -------------------------------- ### Create a Filter Type Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/basics.md Extend AbstractType to define filter fields using the bundle's provided filter types. ```php add('name', Filters\TextFilterType::class); $builder->add('rank', Filters\NumberFilterType::class); } public function getBlockPrefix() { return 'item_filter'; } public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults(array( 'csrf_protection' => false, 'validation_groups' => array('filtering') // avoid NotBlank() constraint-related message )); } } ``` -------------------------------- ### Base Template Structure for Pagerfanta List Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/advanced-usage-with-pagerfanta-bundle.md Defines the layout for a list view including a filter form, data table, and pagination controls. ```html {% trans_default_domain 'admin' %} {% block preList '' %} {% if form is not none %}
{{ form_start(form, {attr: {class: 'form-inline'}}) }}
{% block formFilterRows '' %}
{{ form_end(form) }}
{% endif %}
{{ pager.count }} results {% block tableTh '' %} {% block tableAction %} {% endblock %} {% for object in pager.currentPageResults %} {% block tableTd '' %} {% block tableEdit %} {% endblock %} {% endfor %}
actions
{% block pagination %} {% endblock %}
``` -------------------------------- ### Defining a custom filter event listener Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/working-with-the-bundle.md Implement custom filter logic by listening to specific events generated based on the form type and field name. ```php add('position', Filters\\NumberFilterType::class); } } ``` ```php namespace MyBundle\\EventListener; use Spiriit\\Bundle\\FormFilterBundle\\Event\\GetFilterConditionEvent; class ItemPositionFilterConditionListener { public function onGetFilterCondition(GetFilterConditionEvent $event) { $expr = $event->getFilterQuery()->getExpr(); $values = $event->getValues(); if (!empty($values['value'])) { // create a parameter name from the field $paramName = sprintf('p_%s', str_replace('.', '_', $field)); // Set the condition on the given event $event->setCondition( $expr->eq($event->getField(), ':' . $paramName), array($paramName => $values['value']) ); } } } ``` ```xml ``` -------------------------------- ### Define Twig Component for List Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/advanced-usage-with-pagerfanta-bundle.md Use a Twig component to handle the form view and pager data for list rendering. ```php #[AsTwigComponent(name: 'crud-list', template: 'components/crud/list.html.twig')] class ListComponent { public ?FormView $form = null; public ?Pagerfanta $pager = null; /** * @param mixed[] $data * * @return mixed[] */ #[PreMount] public function preMount(array $data): array { $resolver = new OptionsResolver(); $resolver->setDefault('form', null); $resolver->setRequired('pager'); $resolver->setAllowedTypes('form', ['null', FormView::class]); $resolver->setAllowedTypes('pager', Pagerfanta::class); return $resolver->resolve($data); } } ``` -------------------------------- ### Apply Filters in Controller Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/README.md Handle the filter form request and update the Doctrine QueryBuilder with filter conditions. ```php class DefaultController extends AbstractController { public function __invoke( Request $request, FormFactoryInterface $formFactory, EntityManagerInterface $em, FilterBuilderUpdater $filterBuilderUpdater ): Response { $form = $formFactory->create(RankFilterType::class); $form->handleRequest($request); $filterBuilder = $em ->getRepository(MyEntity::class) ->createQueryBuilder('e'); $filterBuilderUpdater->addFilterConditions($form, $filterBuilder); // now look at the DQL =) dump($filterBuilder->getDql()); return $this->render('testFilter.html.twig', [ 'form' => $form, ]); } } ``` -------------------------------- ### Create a Filter Form Type Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/README.md Define a form class using the provided filter types to specify filtering criteria. ```php add('name', Filters TextFilterType::class); $builder->add('rank', Filters NumberFilterType::class); } } ``` -------------------------------- ### Render Filter Form in Template Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/basics.md Use the form object in a Twig template to display the filter inputs. ```html
{{ form_rest(form) }}
``` -------------------------------- ### Register the FilterSubscriber as a service Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/working-with-the-bundle.md Define the subscriber in your service configuration with the kernel.event_subscriber tag. ```xml ``` -------------------------------- ### Use CollectionAdapterFilterType with Doctrine Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/working-with-the-bundle.md Embed a filter type using CollectionAdapterFilterType and define necessary joins via the add_shared option. ```php add('name', Filters\TextFilterType::class); $builder->add('rank', Filters\NumberFilterType::class); $builder->add('options', Filters\CollectionAdapterFilterType::class, [ 'entry_type' => OptionsFilterType::class, 'add_shared' => function (FilterBuilderExecuterInterface $qbe) { $closure = function (QueryBuilder $filterBuilder, $alias, $joinAlias, Expr $expr) { // add the join clause to the doctrine query builder // the where clause for the label and color fields will be added automatically with the right alias // later by the Spiriit\Filter\QueryBuilderUpdater $filterBuilder->leftJoin($alias . '.options', $joinAlias); }; // then use the query builder executor to define the join and its alias. $qbe->addOnce($qbe->getAlias().'.options', 'opt', $closure); }, ]); } } ``` -------------------------------- ### Apply filter conditions to a query builder Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/working-with-the-bundle.md Use the query builder updater to add filter conditions to a query builder after validating the filter form. ```php // Handle the filtering $filterForm = $this->createForm(new OrderFilterType()); $filterForm->handleRequest($request); if ($filterForm->isValid()) { $filterBuilder = $queryBuilderUpdater->addFilterConditions($filterForm, $filterBuilder); } ``` -------------------------------- ### Disable filtering for a field Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/working-with-the-bundle.md Set the apply_filter option to false to prevent the bundle from adding a condition for a specific field. ```php add('name', Filters\TextFilterType::class, [ 'apply_filter' => false, // disable filter ]); } } ``` -------------------------------- ### Define a RelatedOptionsType filter Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/working-with-the-bundle.md A simple filter type definition containing text and number fields to be used as a subtype. ```php add('label', Filters TextFilterType::class); $builder->add('rank', Filters NumberFilterType::class); } } ``` -------------------------------- ### Implement EmbeddedFilterTypeInterface for AddressFilterType Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/working-with-the-bundle.md Implement the EmbeddedFilterTypeInterface to allow the FilterBuilderUpdater to correctly handle embedded types. ```php namespace Project\Bundle\SuperBundle\Filter; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Spiriit\Bundle\FormFilterBundle\Filter\Form\Type\EmbeddedFilterTypeInterface; use Spiriit\Bundle\FormFilterBundle\Filter\Form\Type as Filters; class AddressFilterType extends AbstractType implements EmbeddedFilterTypeInterface { public function buildForm(FormBuilderInterface $builder, array $options) { $builder->add('street', Filters\TextFilterType::class); $builder->add('postalCode', Filters\NumberFilterType::class); // ... } } ``` -------------------------------- ### Create a custom ItemFilterType Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/working-with-the-bundle.md Define a filter type that extends SharedableFilterType to enable the add_shared option for related entity filtering. ```php namespace Project\Bundle\SuperBundle\Filter; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Spiriit\Bundle\FormFilterBundle\Filter\Form\Type as Filters; class ItemFilterType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder->add('name', Filters\TextFilterType::class); } public function getParent() { return Filters\SharedableFilterType::class; // this allows us to use the "add_shared" option } } ``` -------------------------------- ### Embed filter types in UserFilterType Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/working-with-the-bundle.md Standard form type implementation that embeds another filter type. ```php namespace Project\Bundle\SuperBundle\Filter; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; class UserFilterType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { // ... $builder->add('address', AddressFilterType::class); // ... } } ``` -------------------------------- ### Define an embedded filter type Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/working-with-the-bundle.md Create a standard form type to serve as the embedded filter for related entities. ```php add('label', Filters\TextFilterType::class); $builder->add('color', Filters\TextFilterType::class); } } ``` -------------------------------- ### Customizing filter logic with apply_filter Source: https://github.com/spiriitlabs/form-filter-bundle/blob/master/Resources/doc/working-with-the-bundle.md Use the apply_filter closure to define custom query conditions directly within a form type. This prevents the QueryBuilderUpdater from triggering default events. ```php add('name', Filters\\TextFilterType::class, array( 'apply_filter' => function (QueryInterface $filterQuery, $field, $values) { if (empty($values['value'])) { return null; } $paramName = sprintf('p_%s', str_replace('.', '_', $field)); // expression that represents the condition $expression = $filterQuery->getExpr()->eq($field, ':'.$paramName); // expression parameters $parameters = [$paramName => $values['value']]; // [ name => value ] // or if you need to define the parameter's type // $parameters = [$paramName => [$values['value'], \PDO::PARAM_STR]]; // [ name => [value, type] ] return $filterQuery->createCondition($expression, $parameters); }, )); } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.