Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Multi Search Bundle Laravel Package

petkopara/multi-search-bundle

Symfony bundle that adds a Multi Search service and form type for Doctrine. Build a QueryBuilder to search across all or selected entity columns using a single term, with optional wildcard matching, and reuse it in your controllers or forms.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require petkopara/multi-search-bundle
    

    Register the bundle in config/bundles.php (Symfony 4+) or AppKernel.php (Symfony 3):

    Petkopara\MultiSearchBundle\PetkoparaMultiSearchBundle::class => ['all' => true],
    
  2. First Use Case: Inject the service into a controller and apply multi-search to a QueryBuilder:

    use Petkopara\MultiSearchBundle\Service\MultiSearchBuilder;
    
    public function indexAction(Request $request, MultiSearchBuilder $multiSearch)
    {
        $searchTerm = $request->query->get('search');
        $qb = $this->getDoctrine()->getRepository('AppBundle:Post')->createQueryBuilder('p');
    
        if ($searchTerm) {
            $qb = $multiSearch->searchEntity($qb, 'AppBundle:Post', $searchTerm);
        }
    
        return $this->render('post/index.html.twig', [
            'posts' => $qb->getQuery()->getResult()
        ]);
    }
    
  3. Form Integration: Create a form type with MultiSearchType:

    use Petkopara\MultiSearchBundle\Form\Type\MultiSearchType;
    
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('search', MultiSearchType::class, [
            'class' => 'AppBundle:Post',
            'search_fields' => ['title', 'content'], // Optional
            'search_comparison_type' => 'wildcard' // Optional
        ]);
    }
    

Implementation Patterns

Service-Based Workflow

  1. Dynamic Query Building: Use the service to dynamically modify QueryBuilder instances:

    $qb = $this->getDoctrine()->getRepository('AppBundle:Product')->createQueryBuilder('p');
    $qb = $multiSearch->searchEntity($qb, 'AppBundle:Product', $searchTerm, ['name', 'description'], 'wildcard');
    
  2. Combining with Other Criteria: Chain the multi-search with other query modifications:

    $qb->andWhere('p.isActive = :active')
       ->setParameter('active', true);
    $qb = $multiSearch->searchEntity($qb, 'AppBundle:Product', $searchTerm);
    
  3. Pagination Integration: Use the modified QueryBuilder with KnpPaginatorBundle or native Doctrine pagination:

    $paginator = $this->get('knp_paginator');
    $results = $paginator->paginate(
        $qb,
        $request->query->getInt('page', 1),
        10
    );
    

Form-Based Workflow

  1. Form Handling: Bind the form in the controller and apply the search:

    $form = $this->createForm(PostFilterType::class);
    $form->handleRequest($request);
    
    if ($form->isSubmitted() && $form->isValid()) {
        $qb = $this->getDoctrine()->getRepository('AppBundle:Post')->createQueryBuilder('p');
        $qb = $multiSearch->searchForm($qb, $form->get('search'));
    }
    
  2. Customizing Search Fields: Override search fields per form type:

    $builder->add('search', MultiSearchType::class, [
        'class' => 'AppBundle:User',
        'search_fields' => ['username', 'email', 'fullName']
    ]);
    
  3. Reusing Forms: Extend base form types to avoid repetition:

    class BaseSearchType extends AbstractType
    {
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder->add('search', MultiSearchType::class, [
                'class' => $options['entity_class'],
                'search_fields' => $options['search_fields'] ?? [],
            ]);
        }
    }
    

Advanced Patterns

  1. Event Listeners: Attach multi-search to entity events (e.g., kernel.request):

    public function onKernelRequest(GetResponseEvent $event)
    {
        $request = $event->getRequest();
        if ($request->isMethod('GET') && $request->query->has('search')) {
            // Modify global query logic here
        }
    }
    
  2. API Integration: Use the service in API controllers for search endpoints:

    $qb = $this->getDoctrine()->getRepository('AppBundle:ApiResource')->createQueryBuilder('r');
    $qb = $multiSearch->searchEntity($qb, 'AppBundle:ApiResource', $request->query->get('q'));
    $serializer = $this->get('serializer');
    return new JsonResponse($serializer->serialize($qb->getQuery()->getResult(), 'json'));
    
  3. Dynamic Entity Handling: Pass entity classes dynamically (e.g., from routes):

    $entityClass = $request->attributes->get('entity');
    $qb = $this->getDoctrine()->getRepository($entityClass)->createQueryBuilder('e');
    $qb = $multiSearch->searchEntity($qb, $entityClass, $searchTerm);
    

Gotchas and Tips

Common Pitfalls

  1. Case Sensitivity: The bundle uses LIKE by default, which is case-insensitive in most databases. For case-sensitive searches, use ILIKE (PostgreSQL) or modify the generated DQL:

    // Override the service to customize the comparison
    $this->container->get('petkopara_multi_search.builder')->setComparisonType('custom');
    
  2. Performance with Large Datasets: Avoid searching all columns on large tables. Explicitly define search_fields:

    $qb = $multiSearch->searchEntity($qb, 'AppBundle:Post', $searchTerm, ['title', 'content']);
    
  3. Reserved Keywords: If search terms contain SQL reserved words (e.g., order), escape them or use parameter binding:

    // Ensure the service escapes inputs (check the source for `addLike` method)
    
  4. Form Validation: The MultiSearchType does not validate the search term by default. Add constraints if needed:

    $builder->add('search', MultiSearchType::class, [
        'constraints' => [new Length(['max' => 100])]
    ]);
    

Debugging Tips

  1. Inspect Generated DQL: Log the QueryBuilder before execution to debug:

    $query = $qb->getQuery();
    $this->logger->debug('Generated DQL: ' . $query->getDQL());
    
  2. Check for Typos: Ensure search_fields match entity property names (case-sensitive in some Doctrine configurations).

  3. Service Overrides: Extend the service to add logging or custom logic:

    class CustomMultiSearchBuilder extends MultiSearchBuilder
    {
        public function searchEntity(QueryBuilder $qb, $entity, $searchTerm, array $fields = [], $comparisonType = 'wildcard')
        {
            $this->logger->info('Searching entity: ' . $entity . ' with term: ' . $searchTerm);
            return parent::searchEntity($qb, $entity, $searchTerm, $fields, $comparisonType);
        }
    }
    

    Register the override in services.yaml:

    services:
        petkopara_multi_search.builder:
            class: AppBundle\Service\CustomMultiSearchBuilder
            public: true
    

Extension Points

  1. Custom Comparison Types: Extend the bundle to support new comparison types (e.g., regex):

    // Override the service and add a new method
    public function addRegex(QueryBuilder $qb, $alias, $field, $searchTerm)
    {
        $qb->andWhere("$alias.$field REGEXP :searchTerm")
           ->setParameter('searchTerm', $searchTerm);
    }
    
  2. Entity Metadata Integration: Dynamically fetch searchable fields from entity metadata (e.g., annotations):

    $metadata = $this->getDoctrine()->getManager()->getMetadataFactory()->getMetadataFor($entity);
    $searchFields = array_keys($metadata->fieldMappings);
    
  3. Caching Search Results: Cache the modified QueryBuilder or its results:

    $cacheKey = md5($searchTerm . serialize($fields));
    if (!$results = $cache->get($cacheKey)) {
        $results = $qb->getQuery()->getResult();
        $cache->set($cacheKey, $results, 3600);
    }
    

Configuration Quirks

  1. **Symfony
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui