Oro Documentation
Oro Documentation
  • USERS
  • DEVELOPERS
    • Backend Developer Guide
    • Frontend Developer Guide
    • Bundles & Components
    • Web Services API Guide
    • Community Guide
  • CLOUD
  • BLOG
  • ACADEMY
  • Home >
  • Oro Bundles and Components >
  • OroWebsiteSearchBundle >
  • Perform Search
  • Oro Bundles and Components
    • Components
      • Configuration Merger
      • Cumulative Resources
      • System Aware Resolver
    • ActionBundle
    • ActivityBundle
      • Commands
    • ActivityListBundle
    • AddressBundle
    • ApiBundle
    • AssetBundle
      • Commands
    • AttachmentBundle
      • OroAttachmentBundle Configuration
      • Displaying Pictures
      • Generating Image and File URLs
      • Image Placeholder Configuration
    • BatchBundle
    • CacheBundle
    • CalendarBundle
      • Calendar Provider
      • Calendar Context Menu
      • System Calendars
      • Workflow Action
      • Recurring Events
      • UID (Unique Calendar Identifier)
      • Calendar Event Ownership
      • Attendees
    • ChartBundle
    • CookieConsentBundle
    • CommentBundle
    • ConfigBundle
    • CronBundle
    • CurrencyBundle
      • Multi Currency Cell Content Editor
    • DashboardBundle
    • DataAuditBundle
    • DataGridBundle
      • Default Editors
    • DistributionBundle
    • DigitalAssetBundle
    • ElasticSearchBundle
      • Index Agent and Search Engine
      • ElasticSearch Indexes Backup
      • ElasticSearch Configuration
      • Request Builders
      • Troubleshooting
      • Upgrade Website Index to Elasticsearch >=7.7, <8.0
    • EmailBundle
      • Transports
      • Events
      • Emails
      • Email Templates
      • Email Templates Migrations
      • System Mailboxes
      • Email Ownership
      • Sending Emails in Workflows and Actions (Operations)
      • Recipients Autocompletion
      • Public and Private Emails
      • Commands
    • EmbeddedFormBundle
    • EntityBundle
      • EntityModel
      • EntitySelectSearchApiAccessor ⇐ SearchApiAccessor
      • EntityStructureDataProvider
    • EntityConfigBundle
    • EntityExtendBundle
    • EntityMergeBundle
    • EntityPaginationBundle
    • EntitySerializedFieldsBundle
    • FeatureToggleBundle
    • FilterBundle
      • Filter Form Types
      • Grid Extension
    • FormBundle
      • Form Components Overview
      • Update Handler
      • Entity Create or Select Form Type
      • Rich Text Form Type
      • Autocomplete Form Type
      • Text Autocomplete Form Type
      • UI DataBlock Config Overview
      • Expression Editor
      • Client Side Validation
      • InlineEditableViewComponent
      • Index of Supported Editors
        • AbstractRelationEditorView
        • TextEditorView
        • NumberEditorView
        • PercentEditorView
        • DateEditorView
        • DatetimeEditorView
        • SelectEditorView
        • MultiSelectEditorView
        • MultiCheckboxEditorView
        • MultiRelationEditorView
        • RelatedIdRelationEditorView
        • RelatedIdSelectEditorView
      • Search APIs
    • GaufretteBundle
    • GridFSConfigBundle
    • ImapBundle
      • Usage Example
      • Synchronization with IMAP Servers
      • OAuth Providers for Mailboxes
      • User Email Origin Transport
    • ImportExportBundle
      • Commands
    • InstallerBundle
      • Commands
    • IntegrationBundle
    • LayoutBundle
      • Layout Cache
    • LocaleBundle
      • Locale Settings
      • Number Formatting
      • Date and Datetime Formatting
      • Name Formatting
      • Address Formatting
      • Localization
      • Managing Localizations
      • Current Localization
      • Localized Values
      • CLI Commands (LocaleBundle)
    • LoggerBundle
    • MessageQueueBundle
      • Commands
    • MigrationBundle
      • Commands
    • MicrosoftSyncBundle
    • NavigationBundle
      • Commands
    • NoteBundle
    • NotificationBundle
    • OAuth2ServerBundle
    • OrganizationBundle
    • PlatformBundle
      • Commands
    • QueryDesignerBundle
      • Query Designer Configuration
      • Condition Builder Component
    • RedisConfigBundle
      • Configure Redis Servers
      • Configure Application to Use Redis
    • ReportBundle
    • ScopeBundle
    • SearchBundle
      • ORM Search Engine
      • Search Relevance Weight
      • DateTimeFormatter
    • SecurityBundle
    • SegmentBundle
    • SidebarBundle
    • SyncBundle
      • Configuration
      • Client
      • Topics and Handlers
      • Authentication
      • Content Outdating
      • Origin Checking
      • Mediator Handlers
    • TagBundle
      • TagsEditorView
      • TagsView
    • TestFrameworkBundle
      • Additional Doctrine Events
    • ThemeBundle
    • TranslationBundle
      • Commands
    • TwigInspectorBundle
    • UIBundle
      • Action Manager
      • Client Side Navigation
      • Content Providers
      • Dynamic Assets
      • Formatters
      • Scroll Data Customization
      • TWIG Placeholders
      • TWIG Filters
      • Widgets
      • ApiAccessor
      • BaseClass
      • HiddenInitializationView ⇐ BaseView
      • Layout Subtree View
      • LoadMoreCollection
      • Loading Mask View
      • MultiUseResourceManager ⇐ BaseClass
      • PersistentStorage
      • Highlight Text View
      • RouteModel
      • RoutingCollection
      • SearchApiAccessor
      • Viewport Manager
      • Error Handler
      • Input Widgets
      • Items Manager
      • Mediator Handlers
    • WindowsBundle
    • WorkflowBundle
      • Commands
    • DraftBundle
      • How to Use Drafts
      • How to Use Draft ACL
      • How to Use the Draft Filter
      • How to Resolve Draft Conflicts
      • How to Use a Draft Extension
    • CatalogBundle
    • CheckoutBundle
    • CMSBundle
      • Content Widgets
      • WYSIWYG Field
        • How to Add WYSIWYG Field
        • How to Display a WYSIWYG Field
        • How to Change Textarea Field to WYSIWYG Field
        • WYSIWYG Field Validation
      • Content Blocks
      • Create Editor Components
    • ConsentBundle
      • Add the Customer Consents Field to a Form (Example)
      • Add the Agreements Step to a Custom Checkout Based on the Default Checkout Workflow (Example)
      • Add the Agreements Section to a Custom Checkout Based on the Single Page Checkout Workflow (Example)
    • CustomerBundle
    • FrontendBundle
      • Frontend Sessions and Debug Routes
      • Frontend Access
      • Set Up Mass Action in Datagrid
      • Sticky Panel View
      • Dom Relocation Global View
    • InventoryBundle
    • OrderBundle
      • Previously Purchased Products
    • PayPalBundle
    • PromotionBundle
    • PricingBundle
      • Configure Price List Sharding
      • Optimize Website Indexation and Price Recalculation
      • Combined Price List
      • Price Storage
      • Pricing Strategy
      • Commands
    • ProductBundle
      • Product Actions
      • Product Attributes
      • Product Unit Formatting
      • Product Variant Search
      • Related Items
      • Externally Stored Product Images
      • Product Customization Using Layouts
        • Customize Product View Page
        • Customize Product List Page
        • Customize Product Lists
        • Customize Products SKU Validation
    • RedirectBundle
    • SEOBundle
      • Sitemap
      • SEO Meta Fields
    • TaxBundle
    • WebCatalogBundle
    • WebsiteElasticSearchBundle
      • Website ElasticSearch Search Engine
      • Website ElasticSearch Configuration
      • Attributes Boost
      • Request Builders
      • Upgrade Website Index to Elasticsearch >=7.7, <8.0
      • Synonym Management
    • WebsiteSearchBundle
      • Website Search VS Regular Search
      • Website Search Configuration
      • Search Index Structure
      • Console Commands
      • Perform Search
      • Indexation Process
      • Reindexation During Platform Update
      • ORM Search Engine
      • Search Relevance Weight
      • Testing
    • ActivityContactBundle
    • AnalyticsBundle
    • ChannelBundle
    • SalesBundle
    • ApruveBundle
    • AuthorizeNetBundle
    • DotmailerBundle
    • DPDBundle
    • GoogleTagManagerBundle
    • InfinitePayBundle
    • MailchimpBundle
    • MakerBundle
    • PaypalExpressBundle
    • StripeBundle
  • Contents
    • Search Engine
    • Search Query
    • Search Repository

Perform Search

Search Engine

Search engine is an entry point in Oro application that is used to perform search request. Search engine implements Oro\Bundle\SearchBundle\Engine\EngineInterface interface with one method - search(Query $query, array $context = []).

This method accepts a low level query object (Oro\Bundle\SearchBundle\QueryQuery), sends a request to the search engine and returns result object (Oro\Bundle\SearchBundle\QueryResult). The $context variable may be used to pass additional parameters specific for the search engines. A default website search engine is accessible via the oro_website_search.engine service.

Search Engine

Every engine may have its own requests to modify the way request is sent. However, every engine should support the Oro\Bundle\WebsiteSearchBundle\Event\BeforeSearchEvent out of the box. This event is triggered before the engine queries the search index storage, so the developer can check request parameters and modify the query according to the business logics.

The event name - oro_website_search.before_search - can be used to add a new listener.

Here is an example of such listener definition:

services:
    oro_product.product_visibility_restriction_listener:
        class: Oro\Bundle\ProductBundle\EventListener\ProductVisibilityRestrictionListener
        arguments:
            - '@oro_product.product.manager'
            - '@oro_website_search.provider.search_mapping'
        tags:
            - { name: kernel.event_listener, event: oro_website_search.before_search, method: process }

Search Query

Developer may start constructing a search query by adjusting the Oro\Bundle\SearchBundle\Query\Query example.

Let’s assume there is a product entity with the following index structure:

Oro\Bundle\ProductBundle\Entity\Product:
    alias: oro_product
    fields:
        -
            name: sku
            type: text
        -
            name: name
            type: text
        -
            name: price
            type: decimal

and you want the following query to be executed:

SELECT
    text.sku,
    text.name,
    decimal.price
FROM
    oro_product
WHERE
    text.name ~ product
ORDER_BY
    decimal.price ASC

The following example illustrates how to build and execute such a query:

use Oro\Bundle\SearchBundle\Query\Query;
use Oro\Bundle\SearchBundle\Query\Result;
use Oro\Bundle\SearchBundle\Query\Criteria\Criteria;
use Oro\Bundle\SearchBundle\Engine\EngineInterface;

$query = new Query();
$query
    ->addSelect(['text.sku', 'text.name', 'decimal.price'])
    ->from('oro_product');
$query->getCriteria()
    ->andWhere(Criteria::expr()->contains('text.name', 'product'))
    ->orderBy(['decimal.price' => Query::ORDER_ASC]);

/** @var EngineInterface $engine */
$engine = $this->getContainer()->get('oro_website_search.engine');

/** @var Result $engine */
$result = $engine->search($query);

Where the $result variable is an Oro\Bundle\SearchBundle\Query\Result object that contains collection of Oro\Bundle\SearchBundle\Query\Result\Item objects. Every object in the collection contains information about an entity involved in a search query: entity class, entity ID and additional selected data.

This type of query is used when the search engine and its configuration is unknown, and you need an instance of an engine which implements Oro\Bundle\SearchBundle\Engine\EngineInterface.

As a universal, search-engine agnostic solution, you may use the Oro\Bundle\WebsiteSearchBundle\Query\WebsiteSearchQuery that implements the Oro\Bundle\SearchBundle\Query\SearchQueryInterface interface. This type does not require additional search-engine-specific parameters and can be used in components that should be able to work with any search engine. Basically, such query encapsulates previous type of query and the required parameters to perform search (in this case it is a search engine).

To create the latter type of query, you can use specific factory for website search, or use the generic one and specify the index you used:

$query = $this->container->get('oro_website_search.query_factory')->create();
// OR
$query = $this->container->get('oro_search.query_factory')->create(['search_index' => 'website']);

Let’s execute the request to the search index mentioned above using second type of query:

use Oro\Bundle\SearchBundle\Query\SearchQueryInterface;
use Oro\Bundle\SearchBundle\Query\Result;
use Oro\Bundle\SearchBundle\Query\Criteria\Criteria;

/** @var SearchQueryInterface $query */
$query = $this->container->get('oro_website_search.query_factory')->create();
$query
    ->addSelect(['text.sku', 'text.name', 'decimal.price'])
    ->setFrom('oro_product')
    ->addWhere(Criteria::expr()->contains('text.name', 'product'))
    ->setOrderBy('decimal.price', Query::ORDER_ASC);

/** @var Result $engine */
$result = $query->getResult();

As you can see, the interface is similar, but you are not aware about search engine and index type that is used. This information is resolved on the factory level, so you can override and decorate the service that represents the factory to customize search behavior.

Note

There is a hard limit of 1000 on quantity of results which search query can return.

Search Repository

To store custom queries that are used to receive data from the search index, SearchBundle provides the search repository class – Oro\Bundle\SearchBundle\Query\SearchRepository – with default logic. The WebsiteSearchBundle extends this class and adds Oro\Bundle\WebsiteSearchBundle\Query\WebsiteSearchRepository. The only difference between these repositories is the type of index that is used. Basic repository uses default index from SearchBundle, and the website search repository uses website search index.

You may want to use website repository to create a specialized repository for an entity in the website search index. Similar to the Doctrine object repository, you can use this one to store the website search related methods.

Let’s have a look at the example of such repository:

namespace Oro\Bundle\ProductBundle\Search;

use Oro\Bundle\SearchBundle\Query\Criteria\Criteria;
use Oro\Bundle\SearchBundle\Query\Query;
use Oro\Bundle\SearchBundle\Query\Result;
use Oro\Bundle\SearchBundle\Query\SearchQueryInterface;
use Oro\Bundle\WebsiteSearchBundle\Query\WebsiteSearchRepository;

class ProductRepository extends WebsiteSearchRepository
{
    /**
     * @param string $string
     * @return Result
     */
    public function findByAllText($string)
    {
        /** @var SearchQueryInterface $query */
        $query = $this->createQuery();
        $query
            ->addSelect(['text.sku', 'text.name', 'decimal.price'])
            ->addWhere(Criteria::expr()->contains('text.name', $string))
            ->setOrderBy('decimal.price', Query::ORDER_ASC);

        return $query->getResult();
    }
}

This is exactly the same query described before encapsulated in the repository. No need to call the factory methods. Define this repository as a service and use it wherever you need it.

Below is an example of search repository service declaration:

services:
    oro_product.website_search.repository.product:
        parent: oro_website_search.repository.abstract
        class: Oro\Bundle\ProductBundle\Search\ProductRepository
        calls:
            - [setEntityName, ['Oro\Bundle\ProductBundle\Entity\Product']]

Parent oro_website_search.repository.abstract service already contains all required constructor arguments. You may specify the entity name to automatically fill the FROM part of the query. This call is optional. If it is missing, an empty query will be created.

Oro Documentation
  • Oro inc
  • OroCommerce
  • OroMarketplace
  • OroCRM
  • OroPlatform
  • Partners
  • Services
  • Events
  • Twitter
  • Terms & conditions
  • Privacy policy
  • Contributor license agreement

@2021 Oro, Inc. All Rights Reserved.

Back to top