Read from the package's own PHP files at the commit b5f0c6ba61d0: its namespaces, classes, interfaces and enums, their public constants, properties and methods with their PHPDoc, and the options its factories take. Nothing of it is run.
RegistryclassThe application's connections by name, each made once by its engine's factory from its options:
6 methods
DoctrineObjectStoreclassDoctrine'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
IndexListenerclassThe indexing rule on Doctrine's events: register it on an EventManager (self::EVENTS), or let Bridge\Symfony do it.
6 methods · 1 constant
HostinterfaceAn 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
IndexErrorLoggerclassThe 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
OmnisearchBundleclassOmnisearch in a Symfony application:
3 methods
Omnisearch\Bridge\Symfony\Command
IndexesCommandclass1 method
SchemaCommandclass1 method
BatchclassWrites 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
ConnectionclassA named engine: the driver a connection's configuration made, and the calls an application makes on it.
8 methods · 1 property
DriverinterfaceWhat 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
DriverFactoryinterfaceMakes the drivers of one engine from a connection's options.
2 methods
FacetclassThe values of a field among the documents found, with their counts.
1 method · 3 properties
FilterclassA 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
HitclassA 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
RequestclassA 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
ResponseclassWhat 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
DriverExceptionclassThe 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...).
InvalidConfigExceptionclassA connection or a driver that is not configured, or not installed.
MappingExceptionclassAn index or a field declared in a way that cannot work.
OmnisearchExceptionclassEvery 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.
AttributeLoaderclassReads #[Index] and #[Field] into ClassMetadata - with reflection only, no framework, no engine.
2 methods
ClassMetadataclassWhat 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
FieldclassA 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
FieldMetadataclassA 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
IndexclassA class whose objects are documents of a search index - declared on the class itself, whatever the engine behind:
1 method · 3 properties
MetadataRegistryclassThe 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
TypeclassThe 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
IdentityclassAn object identified by its getId(), or its public $id; loads nothing back. The memory engine's store when the application gives none.
2 methods
MemoryDriverclassAn 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
MemoryDriverFactoryclassThe "memory" engine: MemoryDriver, with the store that identifies the objects (their getId() by default).
3 methods
FinderclassThe 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
IndexerclassThe 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
ManagerclassThe 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
ObjectStoreinterfaceWhere 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
PropertyReaderclassReads 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
QueryclassA search, written fluently and the same for every engine:
15 methods
ResultclassA 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
TransformerclassAn 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
ContractDocumentclassThe document DriverContractTests indexes, for an engine that indexes any object (the memory engine's Identity store reads its id).
2 methods · 4 properties
DriverContractTeststraitWhat 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): ConnectionRegistry::has()
public function has(string $name): boolRegistry::defaultName()
public function defaultName(): stringRegistry::names()
public function names(): arrayRegistry::driverName()
public function driverName(string $name): stringThe 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): stringDoctrineObjectStore::load()
public function load(ClassMetadata $metadata, array $ids, bool $cacheable = false): arrayIndexListener 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): voidIndexListener::postUpdate()
public function postUpdate(LifecycleEventArgs $args): voidIndexListener::preRemove()
public function preRemove(LifecycleEventArgs $args): voidIndexListener::postRemove()
public function postRemove(LifecycleEventArgs $args): voidIndexListener::postFlush()
public function postFlush(): voidOmnisearch\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): boolWhether 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$optionsthe connection's options
$metadatathe 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): voidOmnisearchBundle 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): voidOmnisearchBundle::prependExtension()
public function prependExtension(ContainerConfigurator $container, ContainerBuilder $builder): voidOmnisearchBundle::loadExtension()
public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): voidOmnisearch\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): selfBatch::remove()
public function remove(Connection $connection, ClassMetadata $metadata, string $id): selfBatch::count()
public function count(): intBatch::commit()
public function commit(?callable $onError = null): int$onErrorwhere a failed call goes; thrown when null
- Returns
the writes sent
Batch::rollBack()
public function rollBack(): voidConnection 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(): DriverConnection::create()
public function create(ClassMetadata $metadata): voidConnection::drop()
public function drop(ClassMetadata $metadata): voidConnection::schema()
public function schema(ClassMetadata $metadata): arrayConnection::index()
public function index(ClassMetadata $metadata, object ...$objects): voidConnection::remove()
public function remove(ClassMetadata $metadata, string ...$ids): voidConnection::search()
public function search(ClassMetadata $metadata, Request $request): ResponseDriver 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): voidThe index described by $metadata, created where it is not (an existing one is left as it is).
Driver::drop()
public function drop(ClassMetadata $metadata): voidThe index dropped, with its documents; nothing when there is none.
Driver::schema()
public function schema(ClassMetadata $metadata): arrayThe 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): voidThe objects' documents written (created or replaced).
Driver::remove()
public function remove(ClassMetadata $metadata, string ...$ids): voidThe documents of these identifiers removed; an unknown one is no error.
Driver::search()
public function search(ClassMetadata $metadata, Request $request): ResponseAn 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(): stringThe engine's name in a connection's configuration ("typesense", "memory").
DriverFactory::create()
public function create(array $options): DriverFacet class
final class Facet Facet.php:8
The values of a field among the documents found, with their counts.
public readonly string $fieldpublic readonly array $valuesin the engine's order (the most frequent first)
public readonly array $extrawhat else the engine says of it
Facet::__construct()
public function __construct(public readonly string $field, public readonly array $values, public readonly array $extra = [])$valuesin the engine's order (the most frequent first)
$extrawhat 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 $fieldpublic readonly string $operatorpublic 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): selfFilter::notEquals()
public static function notEquals(string $field, string|int|float|bool $value): selfFilter::in()
public static function in(string $field, array $values): selfFilter::notIn()
public static function notIn(string $field, array $values): selfFilter::matches()
public function matches(mixed $actual): boolHit 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 $idpublic readonly array $documentpublic readonly array $highlightsthe matched words, by field, in the engine's order
public readonly ?float $scorepublic readonly array $rawthe 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 = [])$highlightsthe matched words, by field, in the engine's order
$rawthe 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 $termpublic readonly array $fieldsthe fields the term is searched in
public readonly array $filtersall of them must hold
public readonly array $facetsthe fields whose values are counted
public readonly ?int $maxFacetValuespublic readonly array $sortby field, in order
public readonly int $pagepublic readonly ?int $perPagepublic readonly array $optionspublic 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)$fieldsthe fields the term is searched in
$filtersall of them must hold
$facetsthe fields whose values are counted
$sortby field, in order
Request::option()
public function option(string $name, mixed $default = null): mixedResponse 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 $foundpublic readonly int $pagepublic readonly array $hitspublic readonly array $facetsby field
public readonly int $statuspublic readonly ?string $errorpublic readonly array $rawthe 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 = [])$facetsby field
$rawthe engine's own answer, without its hits
Response::failed()
public static function failed(int $status, string $error): selfResponse::ok()
public function ok(): boolResponse::ids()
public function ids(): arrayOmnisearch\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): arrayThe 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 $classpublic readonly string $indexpublic readonly ?string $connectionpublic readonly array $fieldsby name, in their declared order
public readonly array $optionsthe 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 = [])$fieldsby name, in their declared order
$optionsthe engine's own settings of the index
ClassMetadata::field()
public function field(string $name): ?FieldMetadataClassMetadata::facets()
public function facets(): array- Returns
the fields that can be counted and filtered on
ClassMetadata::toArray()
public function toArray(): arrayClassMetadata::fromArray()
public static function fromArray(array $metadata): selfField 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 $namepublic readonly string $typepublic readonly ?string $propertypublic readonly bool $facetpublic readonly bool $sortpublic readonly bool $infixpublic readonly bool $optionalpublic readonly ?string $localepublic 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 $namepublic readonly string $typepublic readonly ?string $propertypublic readonly bool $facetpublic readonly bool $sortpublic readonly bool $infixpublic readonly bool $optionalpublic readonly ?string $localepublic 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(): stringThe property path the value is read from: the field's name when none is given.
FieldMetadata::toArray()
public function toArray(): arrayFieldMetadata::fromArray()
public static function fromArray(array $field): selfIndex 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 $namethe index's name for the application (an engine may put a prefix in front of it on its server)
public readonly ?string $connectionthe 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 = [])$namethe index's name for the application (an engine may put a prefix in front of it on its server)
$connectionthe 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): selfMetadataRegistry::fromArray()
public static function fromArray(array $metadata): self$metadataClassMetadata::toArray()s, as a container keeps them
MetadataRegistry::add()
public function add(ClassMetadata $metadata): selfMetadataRegistry::all()
public function all(): arrayMetadataRegistry::has()
public function has(string $indexOrClass): boolMetadataRegistry::find()
public function find(string|object $indexOrClass): ?ClassMetadataThe 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): ClassMetadataType 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): boolOmnisearch\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): stringIdentity::load()
public function load(ClassMetadata $metadata, array $ids, bool $cacheable = false): arrayMemoryDriver 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): voidMemoryDriver::drop()
public function drop(ClassMetadata $metadata): voidMemoryDriver::schema()
public function schema(ClassMetadata $metadata): arrayMemoryDriver::index()
public function index(ClassMetadata $metadata, object ...$objects): voidMemoryDriver::remove()
public function remove(ClassMetadata $metadata, string ...$ids): voidMemoryDriver::search()
public function search(ClassMetadata $metadata, Request $request): ResponseMemoryDriverFactory 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(): stringMemoryDriverFactory::create()
public function create(array $options): DriverOmnisearch\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): ResponseFinder::search()
public function search(Query|Request $query): ResultFinder::facets()
public function facets(array $fields, ?Query $query = null, array $checked = [], bool $sortByValue = false): arrayThe 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)$connectionsnull: all of them
Indexer::supports()
public function supports(object $object): boolIndexer::persisted()
public function persisted(object $object): voidIndexer::updated()
public function updated(object $object): voidIndexer::removing()
public function removing(object $object): voidBefore 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): voidIndexer::flush()
public function flush(): int- Returns
the writes sent
Indexer::clear()
public function clear(): voidManager 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(): RegistryManager::metadata()
public function metadata(): MetadataRegistryManager::store()
public function store(): ?ObjectStoreManager::classMetadata()
public function classMetadata(string|object $indexOrClass): ClassMetadataThe metadata of an index, by its name, a class or an object.
Manager::connection()
public function connection(string|object $indexOrClass): ConnectionThe connection an index lives on.
Manager::finder()
public function finder(string|object $indexOrClass): FinderManager::create()
public function create(): voidEvery index created where it is not.
Manager::drop()
public function drop(): voidEvery index dropped.
Manager::index()
public function index(object ...$objects): voidThese 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): stringThe 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): mixedQuery 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): selfQuery::in()
public function in(string ...$fields): selfThe fields the term is searched in, in order of importance.
Query::where()
public function where(string $field, string|int|float|bool $value): selfThe field holds this value (one of its values, for a list).
Query::whereNot()
public function whereNot(string $field, string|int|float|bool $value): selfQuery::whereIn()
public function whereIn(string $field, array $values): selfQuery::filter()
public function filter(Filter $filter): selfQuery::facet()
public function facet(string ...$fields): selfThe fields whose values are counted among the documents found.
Query::maxFacetValues()
public function maxFacetValues(?int $max): selfQuery::sortBy()
public function sortBy(string $field, string $direction = 'asc'): selfQuery::page()
public function page(int $page): selfQuery::perPage()
public function perPage(?int $perPage): selfQuery::option()
public function option(string $name, mixed $value): selfQuery::cacheable()
public function cacheable(bool $cacheable = true): selfThe engine's answer, and the objects loaded from it, may be kept in the cache.
Query::request()
public function request(): RequestResult 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(): boolResult::status()
public function status(): intResult::error()
public function error(): ?stringResult::found()
public function found(): intResult::page()
public function page(): intResult::totalPages()
public function totalPages(int $perPage): intResult::hits()
public function hits(): arrayResult::objects()
public function objects(): arrayResult::hit()
public function hit(object $object): ?HitThe hit an object was loaded from: its document, its matched words.
Result::facets()
public function facets(array $checked = [], bool $sortByValue = false): arrayThe facets counted, by field: each value with its count and whether the visitor checked it.
$checkedthe values checked, by field
$sortByValuein the order of the values rather than by count
Result::facetsOf()
public static function facetsOf(Response $response, array $checked = [], bool $sortByValue = false): arrayTransformer 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): arrayTransformer::value()
public static function value(FieldMetadata $field, mixed $value): mixedOmnisearch\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 $idpublic readonly string $titlepublic readonly int $rankpublic 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(): stringDriverContractTests 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(): voidDriverContractTests::testARequiredOptionLeftOutIsAConfigurationError()
public function testARequiredOptionLeftOutIsAConfigurationError(): voidDriverContractTests::testTheContractsIndexIsWhatTheSuiteExpects()
public function testTheContractsIndexIsWhatTheSuiteExpects(): voidDriverContractTests::testAnIndexIsCreatedOnceDescribedAndDropped()
public function testAnIndexIsCreatedOnceDescribedAndDropped(): voidDriverContractTests::testDocumentsAreFoundByTheirWords()
public function testDocumentsAreFoundByTheirWords(): voidDriverContractTests::testFiltersHold()
public function testFiltersHold(): voidDriverContractTests::testSortAndPages()
public function testSortAndPages(): voidDriverContractTests::testFacetsCountTheDocumentsFound()
public function testFacetsCountTheDocumentsFound(): voidDriverContractTests::testAWriteReplacesAndARemovalForgets()
public function testAWriteReplacesAndARemovalForgets(): voidDriverContractTests::testAnEngineThatDoesNotAnswerAnswersAStatus()
public function testAnEngineThatDoesNotAnswerAnswersAStatus(): void