Getting Started#

Lets get started with the Search Engine Abstraction Layer library for PHP.

In this part we will show how you can start using SEAL in your project and its basic functions.

Installation#

To install the package you need to use Composer as the packages are registered there. Depending on your project you can decide to use already existing Framework integration of the package or the Standalone version.

If you want to use standalone version use the following package:

composer require schranz-search/seal
The project provides adapters to different search engines, atleast one is required.
Choose the one which fits your needs best:

Install the Meilisearch adapter:

composer require schranz-search/seal-meilisearch-adapter

Configure Schema#

The Schema defines the different Indexes and their Fields. The definition of the fields depends on which data you want to store (text, int, float, …) in the search engine and what you want todo with it later (searchable, filterable, sortable, …).

In this section we will create a first schema for our Index:

When using the Standalone version you need to create a new Index instance as part of the Schema:

<?php

use Schranz\Search\SEAL\Schema\Field;
use Schranz\Search\SEAL\Schema\Index;
use Schranz\Search\SEAL\Schema\Schema;

$schema = new Schema([
    'blog' => new Index('blog', [
        'id' => new Field\IdentifierField('id'),
        'title' => new Field\TextField('title'),
        'description' => new Field\TextField('description'),
        'tags' => new Field\TextField('tags', multiple: true, filterable: true),
    ]),
]);

For a full list of available fields see the Schema documentation. The only required field is the IdentifierField which can appear only once per index.

Configure Engine#

In the next step we will create the engine which will be use our created Schema. The Engine is the main class which will be used to communicate with the search engine. So for all kind of operations like add, remove, search, filter, drop, create, … we need to use the Engine.

It requires an instance of the Adapter which we did install before to connect to the correct Search engine.

When using the Standalone version we need to create a new instance of Engine class to create it. The Engine requires beside the already created Schema also an instance of Adapter which will be used to communicate with the search engine.

Use the following code to create a new Engine using the Meilisearch adapter:

<?php

use Meilisearch\Client;
use Schranz\Search\SEAL\Adapter\Meilisearch\MeilisearchAdapter;
use Schranz\Search\SEAL\Engine;

$client = new Client('http://127.0.0.1:7700');

$engine = new Engine(
    new MeilisearchAdapter($client),
    $schema,
);

Prepare Search Engine#

If you already have your search engine running you can skip this step. Still we want to provide here different docker-compose files to get you started quickly with your favorite search engine.

A instance of Meilisearch can be started with the following docker-compose file:

# docker-compose.yml

services:
  meilisearch:
    image: getmeili/meilisearch:v1.7
    environment:
      MEILI_ENV: development
    ports:
      - "7700:7700"
    healthcheck:
      test: ["CMD-SHELL", "curl --silent --fail localhost:7700/health || exit 1"]
      interval: 5s
      timeout: 5s
      retries: 20
    volumes:
      - meilisearch-data:/data.ms

volumes:
  meilisearch-data:

To start the search engine run the following command:

docker-compose up

Depending on the service after a few seconds up to a minute the service is ready to use. And you can continue with the next step.

Create Indexes#

Before you can use the search engine you need to create the indexes.

When using the Standalone version you need to create the Indexes in your search engines via the Engine instance which was created before:

<?php

// create all indexes
$engine->createSchema();

// create specific index
$engine->createIndex('blog');

Add or Update Documents#

A document in SEAL is a associative array following the structure of the defined Schema. The only required field is the IdentifierField of the Schema.

To add documents to the search engine you need to use the Engine instance. With the following code we can add our first documents to our created index:

<?php

class YourService {
    public function __construct(
        private readonly \Schranz\Search\EngineInterface $engine
    ) {
    }

    public function someMethod()
    {
        $this->engine->saveDocument('blog', [
            'id' => 1,
            'title' => 'My first blog post',
            'description' => 'This is the description of my first blog post',
            'tags' => ['UI', 'UX'],
        ]);

        $this->engine->saveDocument('blog', [
            'id' => 3,
            'title' => 'My seconds blog post',
            'content' => 'This is the description of my second blog post',
            'tags' => ['Tech', 'UX'],
        ]);

        $this->engine->saveDocument('blog', [
            'id' => 3,
            'title' => 'My third blog post',
            'content' => 'This is the description of my third blog post',
            'tags' => ['Tech', 'UI'],
        ]);
    }
}

To update a document you can use the same saveDocument method with the same identifier.

For all kind of indexing operations have a look at the Index Operations documentation.

Search Documents#

In this step we will now search for our documents via a search term. This way we are calling a basic search with a given term to the configured search engine. And get a result of all documents which match the search term (first) and a total count how many exists in the given index.

<?php

class YourService {
    public function __construct(
        private readonly \Schranz\Search\EngineInterface $engine
    ) {
    }

    public function someMethod()
    {
        $result = $this->engine->createSearchBuilder()
            ->addIndex('blog')
            ->addFilter(new \Schranz\Search\SEAL\Search\Condition\SearchCondition('first'))
            ->getResult();

        foreach ($result as $document) {
            // do something with the document
        }

        $total = $result->total();
    }
}

For all kind of search and filters have a look at the Search & Filter Conditions documentation.

Filter Documents#

Not even searching but also filtering the documents are possible. In the following example we will filter by the tags field and get all documents which have the tag UI.

<?php

class YourService {
    public function __construct(
        private readonly \Schranz\Search\EngineInterface $engine
    ) {
    }

    public function someMethod()
    {
        $result = $this->engine->createSearchBuilder()
            ->addIndex('blog')
            ->addFilter(new \Schranz\Search\SEAL\Search\Condition\EqualCondition('tags', 'UI'));
            ->getResult();

        foreach ($result as $document) {
            // do something with the document
        }

        $total = $result->total();
    }
}

For all kind of search and filters have a look at the Search & Filter Conditions documentation.

Reindex Documents#

If you have changed the schema or need to index or reindex all your documents the reindex functionality can be used.

First you need to create a ReindexProvider providing all your documents.

<?php

class BlogReindexProvider implements ReindexProviderInterface
{
    public function total(): ?int
    {
        return 2;
    }

    public function provide(): \Generator
    {
        yield [
            'id' => 1,
            'title' => 'Title 1',
            'description' => 'Description 1',
        ];

        yield [
            'id' => 2,
            'title' => 'Title 2',
            'description' => 'Description 2',
        ];
    }

    public static function getIndex(): string
    {
        return 'blog';
    }
}

After that you can use the reindex to index all documents:

When using the Standalone version you need to reindex the documents in your search engines via the Engine instance which was created before:

<?php

$reindexProviders = [
    new BlogReindexProvider(),
];

// reindex all indexes
$engine->reindex($reindexProviders);

// reindex specific index and drop data before
$engine->reindex($reindexProviders, 'blog', dropIndex: true);

Help needed?#

If you need any help or run into any error feel free to use the Github Discussions of the main repository to ask any questions. Or check there if somebody already solved the same problem.

Next Steps#

These were the basic steps to get started with the Search Engine Abstraction Layer (SEAL). In the next part of the documentation, we will delve deeper into the Schema and explore the various field definitions. After that, we will a short look at the Index Operations and then examine the different conditions of Search & Filter Conditions the abstraction provides.