Aller au contenu

omnisense/omnisearch Référence de l’API

Étage
Famille
Version
1.x
Suite de conformité
branchée, CI rouge
Vérifié en réel
Vérifié en partie
Licence
MIT
composer require omnisense/omnisearch:1.x-dev

Lue dans les fichiers PHP du paquet au commit b5f0c6ba61d0 : ses espaces de noms, classes, interfaces et énumérations, leurs constantes, propriétés et méthodes publiques avec leur PHPDoc, et les options que prennent ses fabriques. Rien n’en est exécuté.

Omnisearch

  • Registry class

    The application's connections by name, each made once by its engine's factory from its options:

    6 methods

Omnisearch\Bridge\Doctrine

  • DoctrineObjectStore class

    Doctrine's entities behind the documents: an entity is identified by its identifier's values (joined by "-" when composite, and split back on loading - every split a value holding "-" allows, the entities whose identify() is the id kept), the hits' entities loaded in one query and put in the order of the hits - on any database.

    3 methods

  • IndexListener class

    The indexing rule on Doctrine's events: register it on an EventManager (self::EVENTS), or let Bridge\Symfony do it.

    6 methods · 1 constant

Omnisearch\Bridge\Symfony

  • Host interface

    An engine whose own Symfony bundle hosts the indexes: the bundle creates them, indexes on Doctrine's events and has its commands, and omnisearch only searches through it. A driver package ships one (omnisearch/typesense: glitchr/typesense-bundle), and OmnisearchBundle calls it before the container is built so that the engine's bundle knows the indexes declared by attributes as if its own configuration declared them; omnisearch's own Doctrine listener then leaves that connection alone.

    2 methods

  • IndexErrorLogger class

    The bundle's Indexer $onError by default (on_index_error: log): a write an engine refuses, or that cannot reach it, during Doctrine's flush is logged as an error, the exception in the context, and the application's flush goes on - the database has committed by then. Without a logger it is left to PHP's error log.

    2 methods

  • OmnisearchBundle class

    Omnisearch in a Symfony application:

    3 methods

Omnisearch\Bridge\Symfony\Command

Omnisearch\DBAL

  • Batch class

    Writes gathered and sent together, like a transaction: objects to index and identifiers to remove, per connection and index, in the order they came (a removal after an indexing of the same document wins). commit() sends them, consecutive writes of the same kind on the same index in one call; rollBack() forgets them. A search engine has no transaction of its own: what was sent before a failure stays sent.

    5 methods

  • Connection class

    A named engine: the driver a connection's configuration made, and the calls an application makes on it.

    8 methods · 1 property

  • Driver interface

    What an engine does for omnisearch, in the engine's own terms: a driver (omnisearch/typesense, Omnisearch\Memory) turns the metadata into its index, the objects into its documents, a Request into its query and its answer into a Response.

    6 methods

  • DriverFactory interface

    Makes the drivers of one engine from a connection's options.

    2 methods

  • Facet class

    The values of a field among the documents found, with their counts.

    1 method · 3 properties

  • Filter class

    A condition on a field's value, the same for every engine; the driver writes it in its own syntax. On a list field, "=" means "holds".

    6 methods · 3 properties · 8 constants

  • Hit class

    A document found: its identifier, its fields as the engine holds them, and per field the words of the term it matched there.

    2 methods · 5 properties

  • Request class

    A search, as every engine is asked it: words in some fields, conditions, facets to count, an order, a page. $options carry what only one engine knows (Typesense's infix, num_typos, pinned_hits...), by its own names: a driver reads those it knows and leaves the others.

    2 methods · 10 properties

  • Response class

    What an engine answered: the documents found on this page, how many in all, the facets counted; or why it could not (a status other than 200 and the engine's message).

    4 methods · 7 properties

Omnisearch\Exception

  • DriverException class

    The engine refused or could not be reached; the code is an HTTP status when the engine gave one (400 a malformed request, 404 no such index, 503 unreachable...).

  • InvalidConfigException class

    A connection or a driver that is not configured, or not installed.

  • MappingException class

    An index or a field declared in a way that cannot work.

  • OmnisearchException class

    Every exception omnisearch and its drivers throw: an engine refusing or not reached (DriverException), a connection or a driver not configured (InvalidConfigException), an index declared in a way that cannot work (MappingException). A call that can never work as written - a Filter with an unknown operator, or "in" without a list - is PHP's \InvalidArgumentException, thrown at once: a mistake in the code, not a failure to catch.

Omnisearch\Mapping

  • AttributeLoader class

    Reads #[Index] and #[Field] into ClassMetadata - with reflection only, no framework, no engine.

    2 methods

  • ClassMetadata class

    What a class's attributes say of its index: the index's name, the connection it lives on, its fields in their order, the engine's options.

    5 methods · 5 properties

  • Field class

    A field of the class's index. On the class it names the field and the property path its value is read from ("translations.title", "tags.slug", "isAudible"); on a property or a method the name and the path default to that property's (a method's name without get/is/has).

    1 method · 9 properties

  • FieldMetadata class

    A field of an index, as the attributes declared it: its name in the document, the property path its value is read from, its type and options.

    4 methods · 9 properties

  • Index class

    A class whose objects are documents of a search index - declared on the class itself, whatever the engine behind:

    1 method · 3 properties

  • MetadataRegistry class

    The application's indexes: by index name, and by class - an object of a sub-class belongs to its nearest declared parent's index.

    8 methods

  • Type class

    The types of a field, the same for every engine; a driver maps each onto its own (Typesense: int32, int64, string[]...). A type ending in "[]" is a list of that type.

    1 method · 12 constants

Omnisearch\Memory

  • Identity class

    An object identified by its getId(), or its public $id; loads nothing back. The memory engine's store when the application gives none.

    2 methods

  • MemoryDriver class

    An engine in the PHP process itself: the documents in an array, a term matched word by word (a word of the term matches a word of a field that starts with it, or that holds it anywhere in an infix field), filters, facets, sort, pages. For tests and for an application's first steps; it keeps nothing once the process ends.

    7 methods

  • MemoryDriverFactory class

    The "memory" engine: MemoryDriver, with the store that identifies the objects (their getId() by default).

    3 methods

Omnisearch\ORM

  • Finder class

    The searches of one index: its documents (raw()), its objects (search(), loaded from the ObjectStore in the order of the hits), its facets.

    4 methods · 1 property

  • Indexer class

    The indexing rule, independent of any persistence's events: an object of a declared class that is persisted or updated is indexed, one that is removed is removed from its index - its identifier taken before it goes (removing()), the removal written after (removed()) - all of it sent on flush(). A persistence's bridge calls it from its events (Bridge\Doctrine\IndexListener for Doctrine's).

    8 methods

  • Manager class

    The application's search, the way an EntityManager is its database: the indexes its classes declare, the connections they live on, a finder per index, the indexing of objects.

    10 methods

  • ObjectStore interface

    Where the objects behind the documents live (Doctrine through Bridge\Doctrine, anything else): what identifies an object in its index, and the objects of identifiers, back from a search.

    2 methods

  • PropertyReader class

    Reads a value from an object by its property path, without a framework: "title", "translations.title" (through a list - an array, a Traversable such as a Doctrine collection: every item), "isAudible" (a method of that name). A segment is read by its getter (get, is, has), a method of its very name, a public property, or an ArrayAccess key; what cannot be read is null. A list at the end is an array whose objects are their __toString(); an array field's value is flattened, a single value of one wrapped.

    1 method

  • Query class

    A search, written fluently and the same for every engine:

    15 methods

  • Result class

    A search's answer for the application: the engine's Response, and the objects of its hits once loaded - in the order of the hits; a hit whose object is gone is left out.

    12 methods · 1 property

  • Transformer class

    An object into its document, by its index's fields: each value read by its property path and given its field's type (a date as a timestamp, a list as a list), the identifier as "id". For the drivers that hold plain documents; an engine's own package may convert objects itself.

    3 methods

Omnisearch\Testing

  • ContractDocument class

    The document DriverContractTests indexes, for an engine that indexes any object (the memory engine's Identity store reads its id).

    2 methods · 4 properties

  • DriverContractTests trait

    What every search engine's driver does, as PHPUnit tests: a driver package's test case (or an application's, for a driver of its own) uses this trait, gives the factory, the options of a working connection and the objects to index - and the suite checks the contract of Omnisearch\DBAL\Driver on three documents:

    10 methods

Omnisearch

Registry class

final class Registry Registry.php:20

The application's connections by name, each made once by its engine's factory from its options:

new Registry([new TypesenseDriverFactory(), new MemoryDriverFactory()], [ 'default' => ['driver' => 'typesense', 'options' => ['url' => 'http://localhost:8108', 'secret' => '...']], 'tests' => ['driver' => 'memory'], ]);

The first connection is the default one unless $default names another.

Registry::__construct()

public function __construct(iterable $factories, readonly array $config, ?string $default = null)

Registry::connection()

public function connection(?string $name = null): Connection

Registry::has()

public function has(string $name): bool

Registry::defaultName()

public function defaultName(): string

Registry::names()

public function names(): array

Registry::driverName()

public function driverName(string $name): string

The engine a connection is configured with ("typesense"...).

Omnisearch\Bridge\Doctrine

DoctrineObjectStore class

final class DoctrineObjectStore implements ObjectStore DoctrineObjectStore.php:19

Doctrine's entities behind the documents: an entity is identified by its identifier's values (joined by "-" when composite, and split back on loading - every split a value holding "-" allows, the entities whose identify() is the id kept), the hits' entities loaded in one query and put in the order of the hits - on any database.

$cacheable makes the query cacheable in the second-level cache, in the entity's region.

DoctrineObjectStore::__construct()

public function __construct(readonly ObjectManager|ManagerRegistry $doctrine)

DoctrineObjectStore::identify()

public function identify(object $object): string

DoctrineObjectStore::load()

public function load(ClassMetadata $metadata, array $ids, bool $cacheable = false): array

IndexListener class

final class IndexListener IndexListener.php:15

The indexing rule on Doctrine's events: register it on an EventManager (self::EVENTS), or let Bridge\Symfony do it.

$entityManager->getEventManager()->addEventListener(IndexListener::EVENTS, new IndexListener($indexer));

const EVENTS = [Events::postPersist, Events::postUpdate, Events::preRemove, Events::postRemove, Events::postFlush]

IndexListener::__construct()

public function __construct(readonly Indexer $indexer)

IndexListener::postPersist()

public function postPersist(LifecycleEventArgs $args): void

IndexListener::postUpdate()

public function postUpdate(LifecycleEventArgs $args): void

IndexListener::preRemove()

public function preRemove(LifecycleEventArgs $args): void

IndexListener::postRemove()

public function postRemove(LifecycleEventArgs $args): void

IndexListener::postFlush()

public function postFlush(): void

Omnisearch\Bridge\Symfony

Host interface

interface Host Host.php:17

An engine whose own Symfony bundle hosts the indexes: the bundle creates them, indexes on Doctrine's events and has its commands, and omnisearch only searches through it. A driver package ships one (omnisearch/typesense: glitchr/typesense-bundle), and OmnisearchBundle calls it before the container is built so that the engine's bundle knows the indexes declared by attributes as if its own configuration declared them; omnisearch's own Doctrine listener then leaves that connection alone.

Host::hosts()

public static function hosts(ContainerBuilder $builder): bool

Whether the engine's bundle is there to host (registered in this application).

Host::prepend()

public static function prepend(ContainerBuilder $builder, string $connection, array $options, array $metadata): void
$options

the connection's options

$metadata

the indexes declared on that connection

IndexErrorLogger class

final class IndexErrorLogger IndexErrorLogger.php:14

The bundle's Indexer $onError by default (on_index_error: log): a write an engine refuses, or that cannot reach it, during Doctrine's flush is logged as an error, the exception in the context, and the application's flush goes on - the database has committed by then. Without a logger it is left to PHP's error log.

IndexErrorLogger::__construct()

public function __construct(readonly ?LoggerInterface $logger = null)

IndexErrorLogger::__invoke()

public function __invoke(\Throwable $e): void

OmnisearchBundle class

final class OmnisearchBundle extends AbstractBundle OmnisearchBundle.php:47

Omnisearch in a Symfony application:

omnisearch: connections: default: { driver: typesense, options: { connection: default } } mappings: ['%kernel.project_dir%/src/Entity'] # the classes declaring an #[Index]; src/ by default on_index_error: log # a write that fails during Doctrine's flush: log, throw, or a service id

public function __construct(Manager $search, Finder $blogArticle) }

The drivers installed are registered (omnisearch/typesense, the memory one), autowired. The indexes are read from the attributes when the container compiles and kept in it. An engine with a Symfony bundle of its own (Host) is handed the indexes of its connections before: that bundle creates and indexes them; omnisearch's Doctrine listener indexes the other connections.

OmnisearchBundle::configure()

public function configure(DefinitionConfigurator $definition): void

OmnisearchBundle::prependExtension()

public function prependExtension(ContainerConfigurator $container, ContainerBuilder $builder): void

OmnisearchBundle::loadExtension()

public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void

Omnisearch\Bridge\Symfony\Command

IndexesCommand class

final class IndexesCommand extends Command IndexesCommand.php:13

IndexesCommand::__construct()

public function __construct(readonly Manager $manager)

SchemaCommand class

final class SchemaCommand extends Command SchemaCommand.php:12

SchemaCommand::__construct()

public function __construct(readonly Manager $manager)

Omnisearch\DBAL

Batch class

final class Batch Batch.php:15

Writes gathered and sent together, like a transaction: objects to index and identifiers to remove, per connection and index, in the order they came (a removal after an indexing of the same document wins). commit() sends them, consecutive writes of the same kind on the same index in one call; rollBack() forgets them. A search engine has no transaction of its own: what was sent before a failure stays sent.

Batch::index()

public function index(Connection $connection, ClassMetadata $metadata, object $object): self

Batch::remove()

public function remove(Connection $connection, ClassMetadata $metadata, string $id): self

Batch::count()

public function count(): int

Batch::commit()

public function commit(?callable $onError = null): int
$onError

where a failed call goes; thrown when null

Returns

the writes sent

Batch::rollBack()

public function rollBack(): void

Connection class

final class Connection Connection.php:11

A named engine: the driver a connection's configuration made, and the calls an application makes on it.

public readonly string $name

Connection::__construct()

public function __construct(public readonly string $name, readonly Driver $driver)

Connection::driver()

public function driver(): Driver

Connection::create()

public function create(ClassMetadata $metadata): void

Connection::drop()

public function drop(ClassMetadata $metadata): void

Connection::schema()

public function schema(ClassMetadata $metadata): array

Connection::index()

public function index(ClassMetadata $metadata, object ...$objects): void

Connection::remove()

public function remove(ClassMetadata $metadata, string ...$ids): void
public function search(ClassMetadata $metadata, Request $request): Response

Driver interface

interface Driver Driver.php:13

What an engine does for omnisearch, in the engine's own terms: a driver (omnisearch/typesense, Omnisearch\Memory) turns the metadata into its index, the objects into its documents, a Request into its query and its answer into a Response.

Driver::create()

public function create(ClassMetadata $metadata): void

The index described by $metadata, created where it is not (an existing one is left as it is).

Driver::drop()

public function drop(ClassMetadata $metadata): void

The index dropped, with its documents; nothing when there is none.

Driver::schema()

public function schema(ClassMetadata $metadata): array

The index as create() describes it to the engine, in the engine's terms - to read, compare, or check against what the engine holds.

Driver::index()

public function index(ClassMetadata $metadata, object ...$objects): void

The objects' documents written (created or replaced).

Driver::remove()

public function remove(ClassMetadata $metadata, string ...$ids): void

The documents of these identifiers removed; an unknown one is no error.

public function search(ClassMetadata $metadata, Request $request): Response

An engine that cannot be reached, or refuses, answers a Response with its status and message rather than throwing.

DriverFactory interface

interface DriverFactory DriverFactory.php:6

Makes the drivers of one engine from a connection's options.

DriverFactory::name()

public function name(): string

The engine's name in a connection's configuration ("typesense", "memory").

DriverFactory::create()

public function create(array $options): Driver

Facet class

final class Facet Facet.php:8

The values of a field among the documents found, with their counts.

public readonly string $field
public readonly array $values

in the engine's order (the most frequent first)

public readonly array $extra

what else the engine says of it

Facet::__construct()

public function __construct(public readonly string $field, public readonly array $values, public readonly array $extra = [])
$values

in the engine's order (the most frequent first)

$extra

what else the engine says of it

Filter class

final class Filter Filter.php:9

A condition on a field's value, the same for every engine; the driver writes it in its own syntax. On a list field, "=" means "holds".

const EQUALS = '='
const NOT_EQUALS = '!='
const IN = 'in'
const NOT_IN = 'not in'
const LOWER = '<'
const LOWER_OR_EQUAL = '<='
const GREATER = '>'
const GREATER_OR_EQUAL = '>='
public readonly string $field
public readonly string $operator
public readonly mixed $value

Filter::__construct()

public function __construct(public readonly string $field, public readonly string $operator, public readonly mixed $value)

Filter::equals()

public static function equals(string $field, string|int|float|bool $value): self

Filter::notEquals()

public static function notEquals(string $field, string|int|float|bool $value): self

Filter::in()

public static function in(string $field, array $values): self

Filter::notIn()

public static function notIn(string $field, array $values): self

Filter::matches()

public function matches(mixed $actual): bool

Hit class

final class Hit Hit.php:9

A document found: its identifier, its fields as the engine holds them, and per field the words of the term it matched there.

public readonly string $id
public readonly array $document
public readonly array $highlights

the matched words, by field, in the engine's order

public readonly ?float $score
public readonly array $raw

the engine's own hit, as it gave it

Hit::__construct()

public function __construct(public readonly string $id, public readonly array $document, public readonly array $highlights = [], public readonly ?float $score = null, public readonly array $raw = [])
$highlights

the matched words, by field, in the engine's order

$raw

the engine's own hit, as it gave it

Hit::matchedTokens()

public function matchedTokens(): array
Returns

every matched word, field after field

Request class

final class Request Request.php:11

A search, as every engine is asked it: words in some fields, conditions, facets to count, an order, a page. $options carry what only one engine knows (Typesense's infix, num_typos, pinned_hits...), by its own names: a driver reads those it knows and leaves the others.

public readonly ?string $term
public readonly array $fields

the fields the term is searched in

public readonly array $filters

all of them must hold

public readonly array $facets

the fields whose values are counted

public readonly ?int $maxFacetValues
public readonly array $sort

by field, in order

public readonly int $page
public readonly ?int $perPage
public readonly array $options
public readonly bool $cacheable

Request::__construct()

public function __construct(public readonly ?string $term = null, public readonly array $fields = [], public readonly array $filters = [], public readonly array $facets = [], public readonly ?int $maxFacetValues = null, public readonly array $sort = [], public readonly int $page = 1, public readonly ?int $perPage = null, public readonly array $options = [], public readonly bool $cacheable = false)
$fields

the fields the term is searched in

$filters

all of them must hold

$facets

the fields whose values are counted

$sort

by field, in order

Request::option()

public function option(string $name, mixed $default = null): mixed

Response class

final class Response Response.php:10

What an engine answered: the documents found on this page, how many in all, the facets counted; or why it could not (a status other than 200 and the engine's message).

public readonly int $found
public readonly int $page
public readonly array $hits
public readonly array $facets

by field

public readonly int $status
public readonly ?string $error
public readonly array $raw

the engine's own answer, without its hits

Response::__construct()

public function __construct(public readonly int $found = 0, public readonly int $page = 1, public readonly array $hits = [], public readonly array $facets = [], public readonly int $status = 200, public readonly ?string $error = null, public readonly array $raw = [])
$facets

by field

$raw

the engine's own answer, without its hits

Response::failed()

public static function failed(int $status, string $error): self

Response::ok()

public function ok(): bool

Response::ids()

public function ids(): array

Omnisearch\Exception

DriverException class

final class DriverException extends OmnisearchException DriverException.php:10

The engine refused or could not be reached; the code is an HTTP status when the engine gave one (400 a malformed request, 404 no such index, 503 unreachable...).

InvalidConfigException class

final class InvalidConfigException extends OmnisearchException InvalidConfigException.php:6

A connection or a driver that is not configured, or not installed.

MappingException class

final class MappingException extends OmnisearchException MappingException.php:6

An index or a field declared in a way that cannot work.

OmnisearchException class

class OmnisearchException extends RuntimeException OmnisearchException.php:14

Every exception omnisearch and its drivers throw: an engine refusing or not reached (DriverException), a connection or a driver not configured (InvalidConfigException), an index declared in a way that cannot work (MappingException). A call that can never work as written - a Filter with an unknown operator, or "in" without a list - is PHP's \InvalidArgumentException, thrown at once: a mistake in the code, not a failure to catch.

Omnisearch\Mapping

AttributeLoader class

final class AttributeLoader AttributeLoader.php:11

Reads #[Index] and #[Field] into ClassMetadata - with reflection only, no framework, no engine.

AttributeLoader::load()

public static function load(string $class): ?ClassMetadata
Returns

null when the class declares no Index

AttributeLoader::scan()

public static function scan(array $directories): array

The metadata of every class declared under these directories with an Index. A file is read for its tokens, and only loaded when it names this namespace: the rest of an application's code is never autoloaded.

Returns

by index name, sorted

ClassMetadata class

final class ClassMetadata ClassMetadata.php:11

What a class's attributes say of its index: the index's name, the connection it lives on, its fields in their order, the engine's options.

Plain values: it can be kept in a compiled container or a cache file (toArray(), fromArray()).

public readonly string $class
public readonly string $index
public readonly ?string $connection
public readonly array $fields

by name, in their declared order

public readonly array $options

the engine's own settings of the index

ClassMetadata::__construct()

public function __construct(public readonly string $class, public readonly string $index, public readonly ?string $connection = null, public readonly array $fields = [], public readonly array $options = [])
$fields

by name, in their declared order

$options

the engine's own settings of the index

ClassMetadata::field()

public function field(string $name): ?FieldMetadata

ClassMetadata::facets()

public function facets(): array
Returns

the fields that can be counted and filtered on

ClassMetadata::toArray()

public function toArray(): array

ClassMetadata::fromArray()

public static function fromArray(array $metadata): self

Field class

final class Field Field.php:20

A field of the class's index. On the class it names the field and the property path its value is read from ("translations.title", "tags.slug", "isAudible"); on a property or a method the name and the path default to that property's (a method's name without get/is/has).

  • $type: one of Type's - the engine maps it onto its own;
  • $facet: its values can be counted and filtered on;
  • $sort: results can be sorted by it (numbers and dates always can on most engines);
  • $infix: it can be matched by the middle of a word, where the engine can;
  • $optional: a document may lack it;
  • $locale: the language its text is tokenized in;
  • $options: the engine's own field settings, by engine name or flat.
public readonly ?string $name
public readonly string $type
public readonly ?string $property
public readonly bool $facet
public readonly bool $sort
public readonly bool $infix
public readonly bool $optional
public readonly ?string $locale
public readonly array $options

Field::__construct()

public function __construct(public readonly ?string $name = null, public readonly string $type = Type::STRING, public readonly ?string $property = null, public readonly bool $facet = false, public readonly bool $sort = false, public readonly bool $infix = false, public readonly bool $optional = false, public readonly ?string $locale = null, public readonly array $options = [])

FieldMetadata class

final class FieldMetadata FieldMetadata.php:9

A field of an index, as the attributes declared it: its name in the document, the property path its value is read from, its type and options.

public readonly string $name
public readonly string $type
public readonly ?string $property
public readonly bool $facet
public readonly bool $sort
public readonly bool $infix
public readonly bool $optional
public readonly ?string $locale
public readonly array $options

FieldMetadata::__construct()

public function __construct(public readonly string $name, public readonly string $type = Type::STRING, public readonly ?string $property = null, public readonly bool $facet = false, public readonly bool $sort = false, public readonly bool $infix = false, public readonly bool $optional = false, public readonly ?string $locale = null, public readonly array $options = [])

FieldMetadata::path()

public function path(): string

The property path the value is read from: the field's name when none is given.

FieldMetadata::toArray()

public function toArray(): array

FieldMetadata::fromArray()

public static function fromArray(array $field): self

Index class

final class Index Index.php:18

A class whose objects are documents of a search index - declared on the class itself, whatever the engine behind:

#[Index('article')] #[Field('title', type: Type::STRINGS, property: 'translations.title')] #[Field('tags', type: Type::STRINGS, property: 'tags.slug', facet: true)] class Article { ... }

$options are the engine's own settings of the index (for Typesense: default_sorting_field, token_separators, symbols_to_index), read by its driver, ignored by the others.

public readonly string $name

the index's name for the application (an engine may put a prefix in front of it on its server)

public readonly ?string $connection

the connection it lives on; the default one when null

public readonly array $options

Index::__construct()

public function __construct(public readonly string $name, public readonly ?string $connection = null, public readonly array $options = [])
$name

the index's name for the application (an engine may put a prefix in front of it on its server)

$connection

the connection it lives on; the default one when null

MetadataRegistry class

final class MetadataRegistry MetadataRegistry.php:11

The application's indexes: by index name, and by class - an object of a sub-class belongs to its nearest declared parent's index.

MetadataRegistry::__construct()

public function __construct(iterable $metadata = [])

MetadataRegistry::fromDirectories()

public static function fromDirectories(array $directories): self

MetadataRegistry::fromArray()

public static function fromArray(array $metadata): self
$metadata

ClassMetadata::toArray()s, as a container keeps them

MetadataRegistry::add()

public function add(ClassMetadata $metadata): self

MetadataRegistry::all()

public function all(): array

MetadataRegistry::has()

public function has(string $indexOrClass): bool

MetadataRegistry::find()

public function find(string|object $indexOrClass): ?ClassMetadata

The metadata of an index by its name, or of a class (or of its nearest declared parent).

MetadataRegistry::get()

public function get(string|object $indexOrClass): ClassMetadata

Type class

final class Type Type.php:10

The types of a field, the same for every engine; a driver maps each onto its own (Typesense: int32, int64, string[]...). A type ending in "[]" is a list of that type.

const STRING = 'string'
const STRINGS = 'string[]'
const INT = 'int'
const INTS = 'int[]'
const BIGINT = 'bigint'
const FLOAT = 'float'
const FLOATS = 'float[]'
const BOOL = 'bool'
const BOOLS = 'bool[]'
const DATETIME = 'datetime'

A date and time: a timestamp in the document.

const GEOPOINT = 'geopoint'

[latitude, longitude]

const ALL = [self::STRING, self::STRINGS, self::INT, self::INTS, self::BIGINT, self::FLOAT, self::FLOATS, self::BOOL, self::BOOLS, self::DATETIME, self::GEOPOINT]

Type::isList()

public static function isList(string $type): bool

Omnisearch\Memory

Identity class

final class Identity implements ObjectStore Identity.php:12

An object identified by its getId(), or its public $id; loads nothing back. The memory engine's store when the application gives none.

Identity::identify()

public function identify(object $object): string

Identity::load()

public function load(ClassMetadata $metadata, array $ids, bool $cacheable = false): array

MemoryDriver class

final class MemoryDriver implements Driver MemoryDriver.php:22

An engine in the PHP process itself: the documents in an array, a term matched word by word (a word of the term matches a word of a field that starts with it, or that holds it anywhere in an infix field), filters, facets, sort, pages. For tests and for an application's first steps; it keeps nothing once the process ends.

MemoryDriver::__construct()

public function __construct(readonly Transformer $transformer)

MemoryDriver::create()

public function create(ClassMetadata $metadata): void

MemoryDriver::drop()

public function drop(ClassMetadata $metadata): void

MemoryDriver::schema()

public function schema(ClassMetadata $metadata): array

MemoryDriver::index()

public function index(ClassMetadata $metadata, object ...$objects): void

MemoryDriver::remove()

public function remove(ClassMetadata $metadata, string ...$ids): void
public function search(ClassMetadata $metadata, Request $request): Response

MemoryDriverFactory class

final class MemoryDriverFactory implements DriverFactory MemoryDriverFactory.php:11

The "memory" engine: MemoryDriver, with the store that identifies the objects (their getId() by default).

MemoryDriverFactory::__construct()

public function __construct(readonly ObjectStore $store = new Identity())

MemoryDriverFactory::name()

public function name(): string

MemoryDriverFactory::create()

public function create(array $options): Driver

Omnisearch\ORM

Finder class

final class Finder Finder.php:14

The searches of one index: its documents (raw()), its objects (search(), loaded from the ObjectStore in the order of the hits), its facets.

public readonly ClassMetadata $metadata

Finder::__construct()

public function __construct(readonly Connection $connection, public readonly ClassMetadata $metadata, readonly ?ObjectStore $store = null)

Finder::raw()

public function raw(Query|Request $query): Response
public function search(Query|Request $query): Result

Finder::facets()

public function facets(array $fields, ?Query $query = null, array $checked = [], bool $sortByValue = false): array

The values of these fields with their counts, among the documents $query finds (all of them when null).

Indexer class

final class Indexer Indexer.php:23

The indexing rule, independent of any persistence's events: an object of a declared class that is persisted or updated is indexed, one that is removed is removed from its index - its identifier taken before it goes (removing()), the removal written after (removed()) - all of it sent on flush(). A persistence's bridge calls it from its events (Bridge\Doctrine\IndexListener for Doctrine's).

A failure to reach an engine does not stop the application's flush: it is handed to $onError, or thrown when there is none.

$connections limits it to some connections: those whose engine is indexed by another listener (a Typesense collection under the bundle's own listener) are left out.

Indexer::__construct()

public function __construct(readonly Manager $manager, readonly mixed $onError = null, readonly ?array $connections = null)
$connections

null: all of them

Indexer::supports()

public function supports(object $object): bool

Indexer::persisted()

public function persisted(object $object): void

Indexer::updated()

public function updated(object $object): void

Indexer::removing()

public function removing(object $object): void

Before the object is gone: its identifier is taken now, by the manager's store - or, on a manager without one, as the memory engine takes it (Memory\Identity: getId(), else a public $id).

Indexer::removed()

public function removed(object $object): void

Indexer::flush()

public function flush(): int
Returns

the writes sent

Indexer::clear()

public function clear(): void

Manager class

final class Manager Manager.php:18

The application's search, the way an EntityManager is its database: the indexes its classes declare, the connections they live on, a finder per index, the indexing of objects.

$manager = new Manager($registry, MetadataRegistry::fromDirectories([__DIR__.'/src/Entity']), $store); $manager->finder(Article::class)->search((new Query('fuji'))->in('title'))->objects();

Manager::__construct()

public function __construct(readonly Registry $registry, readonly MetadataRegistry $metadata, readonly ?ObjectStore $store = null)

Manager::registry()

public function registry(): Registry

Manager::metadata()

public function metadata(): MetadataRegistry

Manager::store()

public function store(): ?ObjectStore

Manager::classMetadata()

public function classMetadata(string|object $indexOrClass): ClassMetadata

The metadata of an index, by its name, a class or an object.

Manager::connection()

public function connection(string|object $indexOrClass): Connection

The connection an index lives on.

Manager::finder()

public function finder(string|object $indexOrClass): Finder

Manager::create()

public function create(): void

Every index created where it is not.

Manager::drop()

public function drop(): void

Every index dropped.

Manager::index()

public function index(object ...$objects): void

These objects indexed now, each in its class's index.

ObjectStore interface

interface ObjectStore ObjectStore.php:12

Where the objects behind the documents live (Doctrine through Bridge\Doctrine, anything else): what identifies an object in its index, and the objects of identifiers, back from a search.

ObjectStore::identify()

public function identify(object $object): string

The identifier of an object's document.

ObjectStore::load()

public function load(ClassMetadata $metadata, array $ids, bool $cacheable = false): array
Returns

those found, in the order of $ids

PropertyReader class

final class PropertyReader PropertyReader.php:15

Reads a value from an object by its property path, without a framework: "title", "translations.title" (through a list - an array, a Traversable such as a Doctrine collection: every item), "isAudible" (a method of that name). A segment is read by its getter (get, is, has), a method of its very name, a public property, or an ArrayAccess key; what cannot be read is null. A list at the end is an array whose objects are their __toString(); an array field's value is flattened, a single value of one wrapped.

PropertyReader::read()

public static function read(object $object, string $path, bool $list = false): mixed

Query class

final class Query Query.php:22

A search, written fluently and the same for every engine:

$query = (new Query('fuji')) ->in('title', 'excerpt', 'content') ->where('state', 'publish') ->where('tags', 'en-musique') ->facet('tags') ->sortBy('publishedAt', 'desc') ->page(2)->perPage(10);

An engine's own parameters go through option() under its names (->option('infix', 'always') for Typesense).

Query::__construct()

public function __construct(?string $term = null)

Query::term()

public function term(?string $term): self

Query::in()

public function in(string ...$fields): self

The fields the term is searched in, in order of importance.

Query::where()

public function where(string $field, string|int|float|bool $value): self

The field holds this value (one of its values, for a list).

Query::whereNot()

public function whereNot(string $field, string|int|float|bool $value): self

Query::whereIn()

public function whereIn(string $field, array $values): self

Query::filter()

public function filter(Filter $filter): self

Query::facet()

public function facet(string ...$fields): self

The fields whose values are counted among the documents found.

Query::maxFacetValues()

public function maxFacetValues(?int $max): self

Query::sortBy()

public function sortBy(string $field, string $direction = 'asc'): self

Query::page()

public function page(int $page): self

Query::perPage()

public function perPage(?int $perPage): self

Query::option()

public function option(string $name, mixed $value): self

Query::cacheable()

public function cacheable(bool $cacheable = true): self

The engine's answer, and the objects loaded from it, may be kept in the cache.

Query::request()

public function request(): Request

Result class

final class Result Result.php:14

A search's answer for the application: the engine's Response, and the objects of its hits once loaded - in the order of the hits; a hit whose object is gone is left out.

public readonly Response $response

Result::__construct()

public function __construct(public readonly Response $response, readonly array $objects = [], readonly ?\Closure $identify = null)

Result::ok()

public function ok(): bool

Result::status()

public function status(): int

Result::error()

public function error(): ?string

Result::found()

public function found(): int

Result::page()

public function page(): int

Result::totalPages()

public function totalPages(int $perPage): int

Result::hits()

public function hits(): array

Result::objects()

public function objects(): array

Result::hit()

public function hit(object $object): ?Hit

The hit an object was loaded from: its document, its matched words.

Result::facets()

public function facets(array $checked = [], bool $sortByValue = false): array

The facets counted, by field: each value with its count and whether the visitor checked it.

$checked

the values checked, by field

$sortByValue

in the order of the values rather than by count

Result::facetsOf()

public static function facetsOf(Response $response, array $checked = [], bool $sortByValue = false): array

Transformer class

final class Transformer Transformer.php:15

An object into its document, by its index's fields: each value read by its property path and given its field's type (a date as a timestamp, a list as a list), the identifier as "id". For the drivers that hold plain documents; an engine's own package may convert objects itself.

Transformer::__construct()

public function __construct(readonly ObjectStore $store)

Transformer::document()

public function document(ClassMetadata $metadata, object $object): array

Transformer::value()

public static function value(FieldMetadata $field, mixed $value): mixed

Omnisearch\Testing

ContractDocument class

final class ContractDocument ContractDocument.php:13

The document DriverContractTests indexes, for an engine that indexes any object (the memory engine's Identity store reads its id).

public readonly string $id
public readonly string $title
public readonly int $rank
public readonly array $labels

ContractDocument::__construct()

public function __construct(public readonly string $id, public readonly string $title, public readonly int $rank = 0, public readonly array $labels = [])

ContractDocument::getId()

public function getId(): string

DriverContractTests trait

trait DriverContractTests DriverContractTests.php:63

What every search engine's driver does, as PHPUnit tests: a driver package's test case (or an application's, for a driver of its own) uses this trait, gives the factory, the options of a working connection and the objects to index - and the suite checks the contract of Omnisearch\DBAL\Driver on three documents:

  • the factory names its engine, the Registry connects it from {driver, options}; a required option left out is an InvalidConfigException;
  • an index is created where it is not (twice is no error), described by schema(), dropped with its documents (twice is no error); a search of an index that is not there answers a failed Response (a status, a message), never an exception;
  • documents are found by a word's prefix in the fields asked, with the words they matched; an empty term finds them all; the filters (=, != , in, not in, <, <=, >, >=; "=" on a list field means "holds") all hold; sort asc and desc; pages (perPage, page, found counts them all); facets count the values of the documents found, the most frequent first;
  • a write replaces the document of the same identifier; remove() forgets it, an unknown identifier is no error;
  • an engine that does not answer (unreachableOptions()) answers a search with a failed Response, and a write with an OmnisearchException.

Each test indexes in an index of its own making and drops it afterwards; a shared server is left as it was (give a random prefix where the engine has one).

final class MemoryDriverContractTest extends TestCase { use DriverContractTests;

    protected function factory(): DriverFactory { return new MemoryDriverFactory(); }
    protected function options(): array { return []; }
    protected function document(string $id, string $title, int $rank, array $labels): object { return new ContractDocument($id, $title, $rank, $labels); }
}

The objects are of a class declaring an index (#[Index]) with the fields title (Type::STRING), rank (Type::INT, sort) and labels (Type::STRINGS, facet), identified by $id: Testing\ContractDocument is one, for an engine that indexes any object; a driver that indexes entities gives one of its own.

Requires phpunit/phpunit (the package's require-dev).

DriverContractTests::testTheFactoryNamesItsEngineAndTheRegistryConnectsIt()

public function testTheFactoryNamesItsEngineAndTheRegistryConnectsIt(): void

DriverContractTests::testARequiredOptionLeftOutIsAConfigurationError()

public function testARequiredOptionLeftOutIsAConfigurationError(): void

DriverContractTests::testTheContractsIndexIsWhatTheSuiteExpects()

public function testTheContractsIndexIsWhatTheSuiteExpects(): void

DriverContractTests::testAnIndexIsCreatedOnceDescribedAndDropped()

public function testAnIndexIsCreatedOnceDescribedAndDropped(): void

DriverContractTests::testDocumentsAreFoundByTheirWords()

public function testDocumentsAreFoundByTheirWords(): void

DriverContractTests::testFiltersHold()

public function testFiltersHold(): void

DriverContractTests::testSortAndPages()

public function testSortAndPages(): void

DriverContractTests::testFacetsCountTheDocumentsFound()

public function testFacetsCountTheDocumentsFound(): void

DriverContractTests::testAWriteReplacesAndARemovalForgets()

public function testAWriteReplacesAndARemovalForgets(): void

DriverContractTests::testAnEngineThatDoesNotAnswerAnswersAStatus()

public function testAnEngineThatDoesNotAnswerAnswersAStatus(): void