### Development Setup Commands (Bash) Source: https://github.com/mezcalito/ux-search/blob/0.x/README.md Provides essential bash commands for setting up the development environment for the Mezcalito UX Search project. This includes cloning the repository, starting Docker, installing dependencies, running tests, and performing code quality checks. ```bash # Clone the repository git clone https://github.com/mezcalito/ux-search.git cd ux-search # Start the Docker development environment make up # Install dependencies make install # Run tests make test # Run code quality checks make ci ``` -------------------------------- ### Complete Product Search Example with Meilisearch Source: https://github.com/mezcalito/ux-search/blob/0.x/docs/usage/meilisearch.md A comprehensive PHP example demonstrating a ProductSearch class using the Meilisearch adapter. It configures adapter parameters for cropping descriptions, highlighting search terms, and specifying retrieved attributes. Additionally, it sets up facets, available hits per page, sorting options, and enables URL rewriting. ```php setAdapterParameters([ // Crop long descriptions MeilisearchAdapter::ATTRIBUTES_TO_CROP_PARAM => ['description'], MeilisearchAdapter::CROP_LENGTH_PARAM => 20, MeilisearchAdapter::CROP_MARKER_PARAM => '...', // Highlight search terms MeilisearchAdapter::ATTRIBUTES_TO_HIGHLIGHT_PARAM => ['name', 'description'], MeilisearchAdapter::HIGHLIGHT_PRE_TAG_PARAM => '', MeilisearchAdapter::HIGHLIGHT_POST_TAG_PARAM => '', // Retrieve specific fields only MeilisearchAdapter::ATTRIBUTES_TO_RETRIEVE_PARAM => [ 'id', 'name', 'description', 'price', 'image', 'brand' ], ]) ->addFacet('type', 'Product Type', null, ['limit' => 10]) ->addFacet('brand', 'Brand') ->addFacet('rating', 'Rating') ->addFacet('price_range', 'Price Range') ->addFacet('price', 'Price', RangeSlider::class) ->setAvailableHitsPerPage([12, 24, 48]) ->addAvailableSort(null, 'Relevance') ->addAvailableSort('price:asc', 'Price ↑') ->addAvailableSort('price:desc', 'Price ↓') ->addAvailableSort('popularity:desc', 'Most Popular') ->enableUrlRewriting() ; } } ``` -------------------------------- ### CSS for Custom Search Highlight Styling Source: https://github.com/mezcalito/ux-search/blob/0.x/docs/usage/algolia.md Example CSS to style the custom search highlights defined using the 'search-highlight' class. ```css .search-highlight { background-color: yellow; font-weight: bold; } ``` -------------------------------- ### Install Mezcalito UX Search with Composer Source: https://github.com/mezcalito/ux-search/blob/0.x/README.md This command installs the Mezcalito UX Search bundle using Composer. It is the standard method for adding the library to your Symfony project. ```bash composer require mezcalito/ux-search ``` -------------------------------- ### Complete Product Search Class with Algolia Adapter (PHP) Source: https://github.com/mezcalito/ux-search/blob/0.x/docs/usage/algolia.md This example demonstrates a complete ProductSearch class extending AbstractSearch, configuring the Algolia adapter with custom highlighting, facets, sorting, and URL rewriting. ```php setAdapterParameters([ // Customize highlighting tags AlgoliaAdapter::ATTRIBUTES_TO_HIGHLIGHT_PARAM => ['name', 'description'], AlgoliaAdapter::HIGHLIGHT_PRE_TAG_PARAM => '', AlgoliaAdapter::HIGHLIGHT_POST_TAG_PARAM => '', // Limit facet values AlgoliaAdapter::MAX_VALUES_PER_FACET_PARAM => 50, // Enable analytics with tags AlgoliaAdapter::ANALYTICS_PARAM => true, AlgoliaAdapter::ANALYTICS_TAGS_PARAM => ['web', 'products'], ]) ->addFacet('type', 'Product Type', null, ['limit' => 10]) ->addFacet('brand', 'Brand') ->addFacet('rating', 'Rating') ->addFacet('price', 'Price', RangeSlider::class) ->addAvailableSort('products_index', 'Relevance') ->addAvailableSort('products_index_price_asc', 'Price ↑') ->addAvailableSort('products_index_price_desc', 'Price ↓') ->setAvailableHitsPerPage([12, 24, 48]) ->enableUrlRewriting() ; } } ``` -------------------------------- ### Complete Product Search with Doctrine Adapter Source: https://github.com/mezcalito/ux-search/blob/0.x/docs/usage/doctrine.md An example of a complete `ProductSearch` class utilizing the Doctrine adapter. It configures search fields, facets, sorting, and filtering for active products. ```php setAdapterParameters([ DoctrineAdapter::SEARCH_FIELDS => ['o.name', 'o.brand', 'o.description'], DoctrineAdapter::QUERY_BUILDER_ALIAS => 'o', DoctrineAdapter::QUERY_BUILDER => function (QueryBuilder $qb) { // Only show active products $qb->andWhere('o.active = :active') ->setParameter('active', true); }, DoctrineAdapter::MAX_FACET_VALUES_PARAM => 30, ]) ->addFacet('o.category', 'Category') ->addFacet('o.brand', 'Brand') ->addFacet('o.price', 'Price', RangeInput::class) ->addAvailableSort('o.price:asc', 'Price ↑') ->addAvailableSort('o.price:desc', 'Price ↓') ->addAvailableSort('o.createdAt:desc', 'Newest') ->setAvailableHitsPerPage([12, 24, 48]) ; } } ``` -------------------------------- ### Set Mezcalito UX Search DSN in .env File Source: https://github.com/mezcalito/ux-search/blob/0.x/README.md This shows examples of how to configure the Mezcalito UX Search DSN in your project's .env file, depending on the adapter you choose (Algolia, Meilisearch, or Doctrine). ```bash # For Algolia MEZCALITO_UX_SEARCH_DEFAULT_DSN=algolia://YOUR_API_KEY@YOUR_APP_ID # For Meilisearch MEZCALITO_UX_SEARCH_DEFAULT_DSN=meilisearch://YOUR_MASTER_KEY@localhost:7700 # For Doctrine ORM MEZCALITO_UX_SEARCH_DEFAULT_DSN=doctrine://default ``` -------------------------------- ### Optimize Facets with Limit Configuration Source: https://github.com/mezcalito/ux-search/blob/0.x/docs/usage/meilisearch.md Improve Meilisearch performance by optimizing facet retrieval. This example shows how to limit the number of facet values returned for a specific attribute (e.g., 'brand') to 20, reducing the complexity and size of facet data. ```php ->addFacet('brand', 'Brand', null, ['limit' => 20]) // Limit facet values ``` -------------------------------- ### Implement UX Search Adapter Factory Interface (PHP) Source: https://github.com/mezcalito/ux-search/blob/0.x/docs/create-own-adapter.md This code implements the `AdapterFactoryInterface` for creating adapter instances from DSN strings. The `support` method checks if the factory can handle a given DSN, and `createAdapter` instantiates and returns the appropriate adapter. This is crucial for the bundle to dynamically create and use custom adapters. ```php 'onPreSearch', ]; } public function onPreSearch(PreSearchEvent $event): void { $query = $event->getQuery(); // Modify the query before search execution $query->addFilter('status', 'published'); } } ``` -------------------------------- ### Create a ResultSet Object (PHP) Source: https://github.com/mezcalito/ux-search/blob/0.x/docs/create-own-adapter.md This PHP code shows how to construct a `ResultSet` object, which aggregates all search results and related metadata. It includes methods to set the total number of results, the array of `Hit` objects, and collections of facet distributions and statistics. ```php use Mezcalito\UxSearchBundle\Search\ResultSet\ResultSet; $resultSet = new ResultSet(); $resultSet->setTotalResults(150); $resultSet->setHits($hits); $resultSet->setFacetDistributions($facetDistributions); $resultSet->setFacetStats($facetStats); ``` -------------------------------- ### Generate a Search Class with Maker Command Source: https://github.com/mezcalito/ux-search/blob/0.x/README.md This command uses the Symfony MakerBundle to generate a new search class. It prompts for index name, search name, and adapter, simplifying initial setup. ```bash php bin/console make:search ``` -------------------------------- ### Render Mezcalito UX Search in Twig Template Source: https://github.com/mezcalito/ux-search/blob/0.x/README.md These examples demonstrate how to render the Mezcalito UX Search component in a Twig template, using both the Twig component syntax and the component function. ```twig {# Using Twig component syntax #} {# Or using component function #} {{ component('Mezcalito:UxSearch:Layout', { name: 'product' }) }} ``` -------------------------------- ### Set Mezcalito UX Search Adapter DSN in .env Source: https://context7.com/mezcalito/ux-search/llms.txt Example environment variable configurations for Mezcalito UX Search's default adapter DSN. Choose one adapter (Algolia, Meilisearch, or Doctrine ORM) based on your needs. ```bash # Algolia MEZCALITO_UX_SEARCH_DEFAULT_DSN=algolia://YOUR_API_KEY@YOUR_APP_ID # Meilisearch MEZCALITO_UX_SEARCH_DEFAULT_DSN=meilisearch://YOUR_MASTER_KEY@localhost:7700 # Doctrine ORM MEZCALITO_UX_SEARCH_DEFAULT_DSN=doctrine://default ``` -------------------------------- ### Highlight Search Terms in Meilisearch Results Source: https://github.com/mezcalito/ux-search/blob/0.x/docs/usage/meilisearch.md Configure adapter parameters to highlight matching search terms within Meilisearch results. This involves specifying which attributes to highlight and defining the pre and post tags to be applied around the matching terms. The provided CSS example shows how to style these highlighted terms. ```php ->setAdapterParameters([ MeilisearchAdapter::ATTRIBUTES_TO_HIGHLIGHT_PARAM => ['name', 'description', 'brand'], MeilisearchAdapter::HIGHLIGHT_PRE_TAG_PARAM => '', MeilisearchAdapter::HIGHLIGHT_POST_TAG_PARAM => '', ]) ``` ```css .text-yellow-400 { background-color: #ffd700; font-weight: 600; padding: 0 2px; } ``` -------------------------------- ### Use Custom Adapter in a Search Class (PHP) Source: https://github.com/mezcalito/ux-search/blob/0.x/docs/create-own-adapter.md This PHP code demonstrates how to use a custom adapter within a search class by leveraging the `#[AsSearch]` attribute. The `adapter` parameter in the attribute specifies which adapter to use for this search. The `build` method is where custom logic for the search can be implemented. ```php 1, 'name' => 'Product', 'price' => 29.99], score: 0.95 ); ``` -------------------------------- ### Elasticsearch Adapter Factory in PHP Source: https://context7.com/mezcalito/ux-search/llms.txt This PHP code defines a factory class for creating Elasticsearch adapters. It implements the AdapterFactoryInterface and supports DSNs starting with 'elasticsearch://'. The factory parses the DSN to extract host and API key, then instantiates the ElasticsearchAdapter. ```php // Factory class namespace App\Search\Adapter; use Mezcalito\UxSearchBundle\Adapter\AdapterFactoryInterface; use Mezcalito\UxSearchBundle\Adapter\AdapterInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; final readonly class ElasticsearchAdapterFactory implements AdapterFactoryInterface { public function __construct(private HttpClientInterface $client) { } public function support(string $dsn): bool { return str_starts_with($dsn, 'elasticsearch://'); } public function createAdapter(string $dsn): AdapterInterface { // Parse DSN: elasticsearch://apikey@localhost:9200 $parsed = parse_url($dsn); $host = sprintf('%s://%s:%d', 'https', $parsed['host'], $parsed['port'] ?? 9200); $apiKey = $parsed['user'] ?? ''; return new ElasticsearchAdapter($this->client, $host, $apiKey); } } ``` -------------------------------- ### Implement UX Search Adapter Interface (PHP) Source: https://github.com/mezcalito/ux-search/blob/0.x/docs/create-own-adapter.md This code defines a custom adapter class that implements the `AdapterInterface` for the UX Search Bundle. It includes the `search` method for performing search operations and `configureParameters` for defining settable adapter parameters. Dependencies include the UX Search Bundle's core interfaces and Symfony's OptionsResolver. ```php setDefaults([ 'my_param' => 'my_value', ]); $resolver->setAllowedTypes('my_param', 'string'); } } ``` -------------------------------- ### Configure UX Search Bundle with Custom Adapter (YAML) Source: https://github.com/mezcalito/ux-search/blob/0.x/docs/create-own-adapter.md This YAML configuration snippet shows how to register a custom adapter with the UX Search Bundle. It sets a default adapter and defines an alias ('myAdapter') pointing to the DSN for the custom adapter. This allows the bundle to use the newly created adapter. ```yaml # config/packages/mezcalito_ux_search.yaml mezcalito_ux_search: default_adapter: 'myAdapter' adapters: myAdapter: 'myAdapter://what_you_need' ``` -------------------------------- ### Modify Algolia Search Results with PostSearchEvent (PHP) Source: https://github.com/mezcalito/ux-search/blob/0.x/docs/usage/algolia.md Integrate with the PostSearchEvent to modify Algolia search results after they are fetched. This example shows how to add computed fields and URLs to each hit. ```php use Mezcalito\UxSearchBundle\Event\PostSearchEvent; ->addEventListener(PostSearchEvent::class, function (PostSearchEvent $event) { foreach ($event->getResultSet()->getHits() as $hit) { $data = $hit->getData(); // Add computed fields $data['discount_percentage'] = $this->calculateDiscount($data); // Add URLs $data['url'] = $this->router->generate('product_show', [ 'id' => $data['objectID'] ]); $hit->setData($data); } }, priority: 10) ``` -------------------------------- ### Combine Highlighting and Cropping for Search Previews Source: https://github.com/mezcalito/ux-search/blob/0.x/docs/usage/meilisearch.md Create effective search result page previews by combining text highlighting and cropping. This Meilisearch adapter configuration highlights matching terms and crops long content to show relevant excerpts, while also optimizing the retrieved fields for efficiency. ```php ->setAdapterParameters([ // Highlight matching terms MeilisearchAdapter::ATTRIBUTES_TO_HIGHLIGHT_PARAM => ['title', 'content'], MeilisearchAdapter::HIGHLIGHT_PRE_TAG_PARAM => '', MeilisearchAdapter::HIGHLIGHT_POST_TAG_PARAM => '', // Crop long content to show relevant excerpt MeilisearchAdapter::ATTRIBUTES_TO_CROP_PARAM => ['content'], MeilisearchAdapter::CROP_LENGTH_PARAM => 30, MeilisearchAdapter::CROP_MARKER_PARAM => '…', // Only retrieve what's needed MeilisearchAdapter::ATTRIBUTES_TO_RETRIEVE_PARAM => [ 'id', 'title', 'content', 'author', 'created_at' ], ]) ``` -------------------------------- ### UX Search Configuration Parameters Source: https://github.com/mezcalito/ux-search/blob/0.x/docs/usage/algolia.md This section lists and describes the various configuration parameters available for the UX Search functionality. These parameters allow for fine-tuning search behavior, result presentation, and analytics. ```APIDOC ## Available Configuration Parameters This endpoint provides information about the configurable parameters for UX Search. ### Method GET ### Endpoint /configuration/ux-search ### Parameters #### Query Parameters None #### Request Body None ### Response #### Success Response (200) - **parameter_name** (string) - The name of the configuration parameter. - **algolia_name** (string) - The corresponding name used in Algolia. - **type** (string) - The data type of the parameter (e.g., bool, string, string[]). - **default_value** (any) - The default value of the parameter. - **description** (string) - A description of what the parameter controls. #### Response Example ```json { "parameters": [ { "constant_name": "ADVANCED_SYNTAX_PARAM", "algolia_name": "advancedSyntax", "type": "bool", "default_value": false, "description": "Enable advanced search syntax (AND, OR, NOT operators)" }, { "constant_name": "ADVANCED_SYNTAX_FEATURES_PARAM", "algolia_name": "advancedSyntaxFeatures", "type": "string[]", "default_value": [ "exactPhrase", "excludeWords" ], "description": "Control which advanced syntax features are enabled" } // ... other parameters ] } ``` ### ALTERNATIVES_AS_EXACT_PARAM Values This parameter accepts the following values: - `'ignorePlurals'` - Treat plural/singular as exact matches - `'singleWordSynonym'` - Treat single-word synonyms as exact matches - `'multiWordsSynonym'` - Treat multi-word synonyms as exact matches - `'ignorePlurals'` - Same as above (can be used multiple times) ``` -------------------------------- ### Customize Hit Template (Twig) Source: https://github.com/mezcalito/ux-search/blob/0.x/README.md Overrides the default hit template to customize how search results are displayed. This example shows how to render product information including image, name, price, and a link to product details. ```twig {# templates/components/Mezcalito/UxSearch/Hits.html.twig #}
{% for hit in this.resultSet.hits %}
{{ hit.name }}

{{ hit.name }}

{{ hit.price|format_currency('EUR') }}

View details
{% endfor %}
``` -------------------------------- ### Define Multiple Search Configurations (PHP) Source: https://github.com/mezcalito/ux-search/blob/0.x/README.md Shows how to configure multiple, distinct search instances within a single application using attributes. Each `AbstractSearch` subclass can be configured with a different index and adapter (e.g., Algolia, Meilisearch, Doctrine ORM). ```php // Product search with Algolia #[AsSearch(index: 'products', adapter: 'algolia')] class ProductSearch extends AbstractSearch { } // Blog search with Meilisearch #[AsSearch(index: 'posts', adapter: 'meilisearch')] class BlogSearch extends AbstractSearch { } // User search with Doctrine #[AsSearch(index: 'App\Entity\User', adapter: 'orm')] class UserSearch extends AbstractSearch { } ``` -------------------------------- ### Configure Meilisearch Adapter Source: https://github.com/mezcalito/ux-search/blob/0.x/docs/usage/meilisearch.md Configure the Meilisearch adapter for the UX Search Bundle by specifying the Meilisearch connection URL. This includes providing the API key and host information, with an option for HTTPS in production environments. Ensure the API key is obtained from the Meilisearch dashboard or use the master key for development. ```yaml # config/packages/mezcalito_ux_search.yaml mezcalito_ux_search: adapters: meilisearch: 'meilisearch://YOUR_API_KEY@localhost:7700' # Or for production with HTTPS: # meilisearch: 'meilisearch://YOUR_API_KEY@search.example.com:443' ``` -------------------------------- ### Custom Product Display in Hits Component (Twig) Source: https://github.com/mezcalito/ux-search/blob/0.x/docs/components/Hits.md This example demonstrates how to customize the rendering of individual search results by overriding the 'hit' block. It shows a basic product card structure with image, title, price, and a link. ```twig {% extends '@MezcalitoUxSearch/Hits.html.twig' %} {% block hit %}
{{ hit.data.name }}

{{ hit.data.name }}

$ {{ hit.data.price }}

View Details
{% endblock %} ``` -------------------------------- ### Render Mezcalito UX Search Layout Component in Twig Source: https://context7.com/mezcalito/ux-search/llms.txt Twig template examples demonstrating how to render the Mezcalito UX Search Layout component. It shows the basic usage with the component name and how to pass additional options. ```twig {# Using Twig component syntax #} {# Or using component function #} {{ component('Mezcalito:UxSearch:Layout', { name: 'product' }) }} {# With additional options passed to build() method #} ``` -------------------------------- ### PHP Product Search Implementation with UX Search Source: https://context7.com/mezcalito/ux-search/llms.txt Demonstrates a full-featured search class for products using the UX Search bundle in PHP. It configures a Doctrine adapter, defines multiple facets (category, brand, price, rating), sets available sorting options, configures pagination, and implements pre-search and post-search event listeners for logging, access control, and result enrichment. ```php setAdapterParameters([ DoctrineAdapter::SEARCH_FIELDS => ['p.name', 'p.description', 'p.brand'], DoctrineAdapter::QUERY_BUILDER_ALIAS => 'p', DoctrineAdapter::QUERY_BUILDER => function (QueryBuilder $qb) use ($options) { $qb->andWhere('p.active = :active') ->andWhere('p.stock > :minStock') ->setParameter('active', true) ->setParameter('minStock', 0); // Apply category filter from options if (!empty($options['category'])) { $qb->andWhere('p.category = :category') ->setParameter('category', $options['category']); } }, DoctrineAdapter::MAX_FACET_VALUES_PARAM => 30, ]) // Facets configuration ->addFacet('p.category', 'Category', null, ['limit' => 10]) ->addFacet('p.brand', 'Brand', null, ['limit' => 20]) ->addFacet('p.color', 'Color', null, ['limit' => 8]) ->addFacet('p.price', 'Price', RangeSlider::class) ->addFacet('p.rating', 'Rating', RangeInput::class) // Sorting options ->addAvailableSort(null, 'Relevance') ->addAvailableSort('p.price:asc', 'Price: Low to High') ->addAvailableSort('p.price:desc', 'Price: High to Low') ->addAvailableSort('p.rating:desc', 'Best Rated') ->addAvailableSort('p.createdAt:desc', 'Newest First') ->addAvailableSort('p.popularity:desc', 'Most Popular') // Pagination ->setAvailableHitsPerPage([12, 24, 48, 96]) // Pre-search: logging and access control ->addEventListener(PreSearchEvent::class, function (PreSearchEvent $event) { $query = $event->getQuery(); $this->logger->info('Product search', [ 'query' => $query->getQueryString(), 'user' => $this->security->getUser()?->getUserIdentifier(), 'filters' => count($query->getActiveFilters()), ]); // Premium users see exclusive products if ($this->security->isGranted('ROLE_PREMIUM')) { $filter = new TermFilter('p.exclusive'); $filter->setValues(['1']); $query->addActiveFilter($filter); } }, priority: 10) // Post-search: enrich results ->addEventListener(PostSearchEvent::class, function (PostSearchEvent $event) { $resultSet = $event->getResultSet(); // Batch fetch stock data $ids = array_map(fn($hit) => $hit->getData()['id'], $resultSet->getHits()); $stockData = $this->productRepository->getStockByIds($ids); foreach ($resultSet->getHits() as $hit) { $data = $hit->getData(); // Generate URLs $data['url'] = $this->router->generate('product_show', ['id' => $data['id']]); // Stock information $data['in_stock'] = ($stockData[$data['id']] ?? 0) > 0; // Discount calculation if (isset($data['originalPrice']) && $data['price'] < $data['originalPrice']) { $data['discount'] = sprintf('-%d%%', round((1 - $data['price'] / $data['originalPrice']) * 100)); } $hit->setData($data); } }); } } ``` -------------------------------- ### Integrate Post-Search Events for Result Modification Source: https://github.com/mezcalito/ux-search/blob/0.x/docs/usage/meilisearch.md Modify search results after they are retrieved from Meilisearch using event listeners. This PHP example demonstrates how to add computed fields, generate URLs, and update hit data within a `PostSearchEvent` listener, allowing for dynamic result manipulation. ```php use Mezcalito\UxSearchBundle\Event\PostSearchEvent; ->addEventListener(PostSearchEvent::class, function (PostSearchEvent $event) { foreach ($event->getResultSet()->getHits() as $hit) { $data = $hit->getData(); // Add computed fields $data['discount'] = $this->calculateDiscount($data['price']); $data['in_stock'] = $this->checkStock($data['id']); // Generate URLs $data['url'] = $this->router->generate('product_show', [ 'slug' => $data['slug'] ]); $hit->setData($data); } }, priority: 2) ``` -------------------------------- ### Create a FacetStat Object (PHP) Source: https://github.com/mezcalito/ux-search/blob/0.x/docs/create-own-adapter.md This PHP snippet illustrates creating a `FacetStat` object, used for numeric range facets such as price or rating. It defines the property, the overall minimum and maximum values in the dataset, and optionally the user's selected range. ```php use Mezcalito\UxSearchBundle\Search\ResultSet\FacetStat; $stat = new FacetStat( property: 'price', min: 0, // Minimum value in dataset max: 999, // Maximum value in dataset userMin: 10, // User selected minimum (optional) userMax: 500, // User selected maximum (optional) ); ``` -------------------------------- ### Configure UX Search Facets with PHP Source: https://github.com/mezcalito/ux-search/blob/0.x/docs/components/Facet/RefinementList.md This PHP code demonstrates how to configure facets for the UX Search component within a custom search class. It uses the `addFacet` method to define facet properties like the attribute, label, and optional configuration such as the display limit. ```php use Mezcalito\UxSearchBundle\Search\AbstractSearch; #[AsSearch('products')] class ProductSearch extends AbstractSearch { public function build(array $options = []): void { $this ->addFacet('brand', 'Brand') ->addFacet('category', 'Category') ->addFacet('color', 'Color', null, ['limit' => 10]) // Show max 10 values ->addFacet('size', 'Size', null, ['limit' => 5]); } } ``` -------------------------------- ### Create a FacetTermDistribution Object (PHP) Source: https://github.com/mezcalito/ux-search/blob/0.x/docs/create-own-adapter.md This PHP code demonstrates creating a `FacetTermDistribution` object, used for facets with discrete values like brands or categories. It allows setting the property name, mapping values to counts, and indicating which values are currently selected by the user. ```php use Mezcalito\UxSearchBundle\Search\ResultSet\FacetTermDistribution; $facet = new FacetTermDistribution(); $facet->setProperty('brand'); $facet->setValues([ 'Nike' => 45, // 45 products 'Adidas' => 32, // 32 products 'Puma' => 18, // 18 products ]); $facet->setCheckedValues(['Nike']); // User selected Nike ``` -------------------------------- ### Configuring Sort Options (PHP) Source: https://github.com/mezcalito/ux-search/blob/0.x/docs/components/SortBy.md This PHP code demonstrates how to define available sort options within a custom Search class by extending `AbstractSearch` and using the `addAvailableSort` method. ```php use Mezcalito\UxSearchBundle\Search\AbstractSearch; #[AsSearch('products')] class ProductSearch extends AbstractSearch { public function build(array $options = []): void { $this ->addAvailableSort('relevance', 'Relevance') ->addAvailableSort('price:asc', 'Price: Low to High') ->addAvailableSort('price:desc', 'Price: High to Low') ->addAvailableSort('name:asc', 'Name: A to Z') ->addAvailableSort('created:desc', 'Newest First') ->addAvailableSort('rating:desc', 'Top Rated') ; } } ``` -------------------------------- ### Render RefinementList in Loop (Twig) Source: https://github.com/mezcalito/ux-search/blob/0.x/docs/components/Facet/RefinementList.md Shows how to iterate over available facets and render the RefinementList component for each one using the generic Facet component. This allows dynamic rendering of multiple refinement lists. ```twig {% for facet in search.facets %} {% endfor %} ``` -------------------------------- ### Optimize Search Performance with Facet Limits and Hits per Page (PHP) Source: https://github.com/mezcalito/ux-search/blob/0.x/docs/usage/customize-your-search.md This snippet demonstrates how to optimize search performance in Mezcalito by limiting the number of facet values returned and configuring available 'hits per page' options. It also shows an example of enriching search results efficiently within a PostSearchEvent, fetching only necessary data to reduce overhead. ```php // Limit facet values to improve performance ->addFacet('brand', 'Brand', null, ['limit' => 20]) // Use appropriate hits per page options ->setAvailableHitsPerPage([12, 24, 48]) // Don't offer 100+ // In PostSearchEvent, only enrich necessary data ->addEventListener(PostSearchEvent::class, function (PostSearchEvent $event) { // Only fetch what's needed, not full entities $ids = array_map(fn($hit) => $hit->getData()['id'], $event->getResultSet()->getHits()); $urls = $this->urlRepository->findUrlsByProductIds($ids); // Optimized query // Map URLs to hits foreach ($event->getResultSet()->getHits() as $hit) { $data = $hit->getData(); $data['url'] = $urls[$data['id']] ?? '/'; $hit->setData($data); } }) ``` -------------------------------- ### Wise Use of Cropping for Shorter Excerpts Source: https://github.com/mezcalito/ux-search/blob/0.x/docs/usage/meilisearch.md Implement efficient text cropping in Meilisearch results by setting a concise `CROP_LENGTH_PARAM`. This PHP configuration limits the description to 15 words, ensuring brief and focused previews in search results. ```php ->setAdapterParameters([ MeilisearchAdapter::ATTRIBUTES_TO_CROP_PARAM => ['description'], MeilisearchAdapter::CROP_LENGTH_PARAM => 15, // Keep it short ]) ``` -------------------------------- ### Enable Algolia A/B Testing for Search Configurations (PHP) Source: https://github.com/mezcalito/ux-search/blob/0.x/docs/usage/algolia.md Configure Algolia to enable A/B testing for search parameters, allowing you to test different ranking formulas, synonym configurations, or facet orderings. ```php ->setAdapterParameters([ AlgoliaAdapter::ENABLE_AB_TEST_PARAM => true, ]) ``` -------------------------------- ### Create SEO-Friendly URL Formatter in PHP Source: https://context7.com/mezcalito/ux-search/llms.txt This PHP class implements the UrlFormaterInterface to generate SEO-friendly URLs from search queries and apply filters from rewritten URLs back to the query object. It handles query strings, term filters, range filters, sorting, and pagination. Dependencies include classes from the MezcalitoUxSearchBundle. ```php getQueryString()) { $parts[] = 'q/' . urlencode($queryString); } foreach ($query->getActiveFilters() as $filter) { $property = str_replace('.', '-', $filter->getProperty()); if ($filter instanceof TermFilter) { $values = implode(',', $filter->getValues()); $parts[] = $property . '/' . urlencode($values); } elseif ($filter instanceof RangeFilter) { $parts[] = $property . '/' . $filter->getMin() . '-' . $filter->getMax(); } } if ($sort = $query->getActiveSort()) { $parts[] = 'sort/' . urlencode($sort); } if ($query->getCurrentPage() > 1) { $parts[] = 'page/' . $query->getCurrentPage(); } return $request->getPathInfo() . '/' . implode('/', $parts); // Output: /products/q/laptop/brand/Dell,HP/price/500-1500/sort/price:asc/page/2 } public function applyFilters(CurrentRequest $request, SearchInterface $search, Query $query): void { $path = trim($request->getPathInfo(), '/'); $segments = explode('/', $path); // Skip base path segments $segments = array_slice($segments, 1); for ($i = 0; $i < count($segments); $i += 2) { $key = $segments[$i] ?? null; $value = $segments[$i + 1] ?? null; if (!$key || !$value) continue; match ($key) { 'q' => $query->setQueryString(urldecode($value)), 'page' => $query->setCurrentPage((int) $value), 'sort' => $query->setActiveSort(urldecode($value)), 'brand', 'category' => (function () use ($query, $key, $value) { $filter = new TermFilter(str_replace('-', '.', $key)); $filter->setValues(explode(',', urldecode($value))); $query->addActiveFilter($filter); })(), 'price' => (function () use ($query, $value) { [$min, $max] = explode('-', $value); $filter = new RangeFilter('price'); $filter->setMin((float) $min); $filter->setMax((float) $max); $query->addActiveFilter($filter); })(), default => null, }; } } } ``` -------------------------------- ### Configure Product Search Class in PHP Source: https://github.com/mezcalito/ux-search/blob/0.x/docs/usage/customize-your-search.md Demonstrates a fully configured Search class for products, including adapter settings, facets, sorting, pagination, event listeners for pre- and post-search actions, and URL rewriting. ```php setAdapterParameters([ DoctrineAdapter::SEARCH_FIELDS => ['p.name', 'p.description', 'p.brand'], DoctrineAdapter::QUERY_BUILDER_ALIAS => 'p', DoctrineAdapter::QUERY_BUILDER => function (QueryBuilder $qb) { $qb->andWhere('p.active = :active') ->andWhere('p.stock > :min_stock') ->setParameter('active', true) ->setParameter('min_stock', 0); }, ]) // Facets ->addFacet('p.category', 'Category', null, ['limit' => 10]) ->addFacet('p.brand', 'Brand', null, ['limit' => 20]) ->addFacet('p.rating', 'Rating') ->addFacet('p.price', 'Price', RangeSlider::class) ->addFacet('p.weight', 'Weight (kg)', RangeInput::class) // Sorting options ->addAvailableSort(null, 'Relevance') ->addAvailableSort('p.price:asc', 'Price: Low to High') ->addAvailableSort('p.price:desc', 'Price: High to Low') ->addAvailableSort('p.rating:desc', 'Best Rated') ->addAvailableSort('p.createdAt:desc', 'Newest First') // Pagination ->setAvailableHitsPerPage([12, 24, 48, 96]) // Pre-search event: Log queries ->addEventListener(PreSearchEvent::class, function (PreSearchEvent $event) { $this->logger->info('Product search', [ 'query' => $event->getQuery()->getQuery(), 'user' => $this->security->getUser()?->getEmail(), ]); // Add filter for premium users if ($this->security->isGranted('ROLE_PREMIUM')) { $event->getQuery()->addFilter('p.exclusive', ['true']); } }, priority: 10) // Post-search event: Enrich results ->addEventListener(PostSearchEvent::class, function (PostSearchEvent $event) { foreach ($event->getResultSet()->getHits() as $hit) { $data = $hit->getData(); // Generate URL $data['url'] = $this->router->generate('product_show', [ 'id' => $data['id'] ]); // Add discount badge if ($data['discount'] > 0) { $data['badge'] = sprintf('-%d%%', $data['discount']); } $hit->setData($data); } }, priority: 5) // URL rewriting ->enableUrlRewriting() ; } } ``` -------------------------------- ### Render Pagination Component (Twig) Source: https://github.com/mezcalito/ux-search/blob/0.x/docs/components/Pagination.md Demonstrates how to render the Pagination component within a Twig template. This is the primary method for integrating the pagination system into your application's UI. No external dependencies are required beyond the component itself. ```twig ``` -------------------------------- ### Implement Search Analytics with Event Subscriber (PHP) Source: https://context7.com/mezcalito/ux-search/llms.txt This snippet shows how to create a PHP event subscriber to track search analytics. It listens for pre- and post-search events, measures the search duration, and logs relevant data like query, results, page, and filters using an AnalyticsService. It also demonstrates how to register this subscriber within a Search class. ```php ['onPreSearch', 10], PostSearchEvent::class => ['onPostSearch', 5], ]; } public function onPreSearch(PreSearchEvent $event): void { $this->startTime = microtime(true); } public function onPostSearch(PostSearchEvent $event): void { $duration = (microtime(true) - $this->startTime) * 1000; $this->analytics->track('search_completed', [ 'query' => $event->getQuery()->getQueryString(), 'results' => $event->getResultSet()->getTotalResults(), 'page' => $event->getQuery()->getCurrentPage(), 'duration_ms' => round($duration, 2), 'filters' => count($event->getQuery()->getActiveFilters()), ]); } } // Register subscriber in Search class #[AsSearch('products')] class ProductSearch extends AbstractSearch { public function __construct(private AnalyticsService $analytics) { } public function build(array $options = []): void { $this ->addFacet('brand', 'Brand') ->addEventSubscriber(new SearchAnalyticsSubscriber($this->analytics)) ; } } ```