Index

Query

MMO\core\entities · 1 symbol · generated 5 Oct 2026

class

Query

Query.php:22

Generic way to query a collection of entities.

class MMO\core\entities\Query implements IteratorAggregate, Stringable, MMO\core\interfaces\iSignal use MMO\core\classes\tEvent, MMO\core\classes\tWithOptions
Namespace
MMO\core\entities
Implements
IteratorAggregate, Stringable, iSignal
Uses traits
tEvent, tWithOptions
This class also simplify passing a query through your request. When a query is created, it is sent as a signal, and you can change the returned entities. You can then iterate this object to get the final entities.
foreach ($collection->query(['status' => 'active'])->sort('name')->pagination(20, 0) as $entity) { ... }

Index

collection
customExecuteCustom function for execution function(Query $query, array $options)
entities
fields
filtersFilter options A list of operators and/or array of json path/values.
isList
limit
Listeners static
offsetPagination
opts
sorts
total
AddListener($handler, $order) staticRegister a listener directly (as opposed to ConnectListeners's attribute-based discovery).
addOptions($opts, $appendList)Merge $opts into the existing options (through merge), rather than replacing them wholesale like setOptions.
and($args)Add one or more AND-combined filter conditions.
applySort()Re-sort the already-run results in memory by $sorts (defaulting to id descending if none set) -- useful when the entities' order needs to reflect a change made after the query ran (e.g.
clear($clearSorts)Reset the query to a blank slate: no results, filters, fields, offset, or limit.
clearEntities()Discard any already-run results (and the cached $total), so the next execute/getReturn re-runs the query.
clearOptions()Empty the options bag.
ConnectListeners($obj) staticScan $obj's methods for #[Listen(EventClass::class)] attributes and register each one as a listener on the matching event class.
debugName()
DisconnectListeners($obj) staticUndo a previous ConnectListeners: removes every listener that connect had registered for $obj on this event class.
dispatch()Invoke every GetListeners listener with $this.
execute($opts)Execute a query
field($path, $visible)
filter($filter)Add a filter condition to this query's root filter group ($filters, an AND group by default).
getEntities()
getFields()
getIterator()\IteratorAggregate::getIterator -- the query's results (running it first if needed -- see getReturn), as a \Traversable either way.
GetListeners() staticCollect every listener for this class, including those registered on its parent classes (so a subclass event is also caught by listeners of its parent event), sorted by ascending $order (ties keep …
getOption($key, $default)
getOptions()
getOrigin()
getReturn()
getSorts()
getVisibleFields()Resolve getFields into the actual list of field names that should be shown: with no explicit selection, every schema-declared visible property; with an explicit selection that only HIDES field…
hasFilters()
HasListener($handler) static
isListOnly()
isRaw()Tells if query's entities will be returned as an array (raw) instead of Entity
listOnly()Only list entities (return entity's id and properties needed in title and label)
listRequiredCollections($filter)List all the other required collections needed for the query
loopRequiredCollection($repository, $schema, $path, $_recusivePath)Recursion helper for listRequiredCollections: walks a single filter path's schema, yielding the collection behind each instance-typed segment it crosses -- including, for a computed 'label'/'t…
nor($args)Add one or more NOR-combined filter conditions.
or($args)Add one or more OR-combined filter conditions.
pagination($limit, $offset)
RemoveListener($handler) staticRemove the last added handler from the listeners.
Send($args) staticConstruct a new instance of this class with $args, then dispatch it to every listener.
setFields($value)NOTE: same bug (and fix) as setSorts -- used to check $value[0] instead of $field[0], so a --prefixed field (meant to hide it) was only ever recognized when it was the very first field i…
SetListenerOrder($handler, $order) staticChange the order of an already-registered listener, whether added directly via AddListener or indirectly via ConnectListeners (which also stores its [$obj, $methodName] callables here).
setListOnly($value)
setOption($key, $value)Set (or, with a null $value, remove) a single option.
setOptions($opts)Replace the whole options bag.
setRaw($raw)
setReturn($entities)
setRootOperator($operator)Change the root filter group's combining operator, wrapping the existing filters in a new group under $operator if it differs from the current one.
setSorts($value)NOTE: this used to check $value[0] === '-' (the LIST's own first element) inside the foreach ($value as $field) loop, instead of $field[0] (the CURRENT field being examined) -- so, except for…
sort($path, $asc)NOTE: $asc used to be typed bool (non-nullable), so the $asc === null check below could never be true -- PHP rejects passing null for a non-nullable parameter with a TypeError before the me…
__clone()Deep-clones $filters (so mutating the clone's filters doesn't affect the original) and discards any already-run results (clearEntities).
__construct($collection, $filter, $fields, $sort, $limit, $offset, $options)
__toString()

Properties12

collection

MMO\core\interfaces\iCollection $collection
Type
iCollection

customExecute

Custom function for execution function(Query $query, array $options)

$customExecute = null

entities

protected ?iterable $entities = null
Type
null | iterable

fields

protected array $fields = []
Type
array

filters

Filter options A list of operators and/or array of json path/values.

MMO\core\helpers\FilterGroup $filters
Type
FilterGroup
Operators are prefixed with `$`. Allowed operators: $or, $and, $nor, $in, $gt (>), $gte (>=), $lt (<), $lte (<=), $regex (regular expression PCRE)

isList

protected bool $isList = false
Type
bool

limit

?int $limit = null
Type
null | int

Listeners

static
protected static array $Listeners = []
Type
array

offset

Pagination

?int $offset = null
Type
null | int

opts

protected array $opts = []
Type
array

sorts

protected array $sorts = []
Type
array

total

?int $total = null
Type
null | int

Methods49

AddListener($handler, $order)

statictEvent.php:62

Register a listener directly (as opposed to ConnectListeners's attribute-based discovery).

static function AddListener(callable $handler, int $order = 0): void
$handlercallablecalled as $handler($eventInstance) when this event class is Send / dispatch-ed
$order = 0intlisteners run in ascending order (lower first); listeners with an equal order run in the order they were added
returnsvoid
UserCreated::AddListener(function (UserCreated $e) {...}, 10);

addOptions($opts, $appendList)

tWithOptions.php:65

Merge $opts into the existing options (through merge), rather than replacing them wholesale like setOptions.

function addOptions(array $opts, bool $appendList = false): void
$optsarraythe options to merge in
$appendList = falseboolif true, a list-valued option is appended to (rather than replaced by) the corresponding list in $opts -- see \MMO\core\arrays\merge for the exact semantics
returnsvoid
$t->setOptions(['a' => 1, 'tags' => ['x']]); $t->addOptions(['b' => 2, 'tags' => ['y']]); $t->getOptions(); // ['a' => 1, 'tags' => ['y'], 'b' => 2] -- 'tags' is replaced, not appended ($appendList=false)

applySort()

Query.php:299

Re-sort the already-run results in memory by $sorts (defaulting to id descending if none set) -- useful when the entities' order needs to reflect a change made after the query ran (e.g. a listener mutated some values), since the repository-side sort can't see that.

function applySort(): void
returnsvoid

clear($clearSorts)

Query.php:166

Reset the query to a blank slate: no results, filters, fields, offset, or limit. @param bool $clearSorts if true, also clear the sort order (kept by default).

function clear(bool $clearSorts = false): void
$clearSorts = falsebool
returnsvoid

clearOptions()

tWithOptions.php:39

Empty the options bag.

function clearOptions(): void
returnsvoid
$t->clearOptions(); // getOptions() === []

ConnectListeners($obj)

statictEvent.php:37

Scan $obj's methods for #[Listen(EventClass::class)] attributes and register each one as a listener on the matching event class. connect does the actual reflection/registration.

static function ConnectListeners(object|string $obj): void
$objobject | stringan instance (or class name, for static-only listener methods)
returnsvoid
throws
class UserService { #[Listen(UserCreated::class, order: 1)] public function onUserCreated(UserCreated $e): void {...} } UserCreated::ConnectListeners(new UserService()); // onUserCreated() is now called on every UserCreated::Send()

DisconnectListeners($obj)

statictEvent.php:49

Undo a previous ConnectListeners: removes every listener that connect had registered for $obj on this event class.

static function DisconnectListeners(object|string $obj): void
$objobject | string
returnsvoid
throws
UserCreated::DisconnectListeners($service); // $service's #[Listen] methods stop firing

dispatch()

tEvent.php:153

Invoke every GetListeners listener with $this. If the class also implements PSR-14's StoppableEventInterface, dispatch stops early as soon as isPropagationStopped() becomes true.

function dispatch(): static
returnsstatic$this, for chaining
(new UserCreated('Marc'))->dispatch(); // what Send() does internally

execute($opts)

Query.php:99

Execute a query

function execute(array $opts = []): iterable
$opts = []array- raw: {bool} if true, won't load entities. Use this when fields are not enough to create a full entity
returnsiterable

field($path, $visible)

Query.php:370
function field(string $path, ?bool $visible = true): self
$pathstring
$visible = truenull | booltrue/false to show/hide $path, or null to remove any explicit selection for it.
returnsself

filter($filter)

Query.php:438

Add a filter condition to this query's root filter group ($filters, an AND group by default). @return iFilter $filter itself, normalized.

function filter(MMO\core\interfaces\iFilter|array|string $filter): MMO\core\interfaces\iFilter
$filteriFilter | array | string
returnsiFilter

getEntities()

Query.php:153
function getEntities(): array
returnsarraythe query's results (running it first if needed), materialized as a plain array (consuming/caching a lazy iterable's items).

getIterator()

Query.php:145

\IteratorAggregate::getIterator -- the query's results (running it first if needed -- see getReturn), as a \Traversable either way.

function getIterator(): Traversable
returnsTraversableT>

GetListeners()

statictEvent.php:123

Collect every listener for this class, including those registered on its parent classes (so a subclass event is also caught by listeners of its parent event), sorted by ascending $order (ties keep insertion order).

static function GetListeners(): array
returnsarray[[callable $handler, int $order], ...]
UserCreated::GetListeners(); // [[$handlerB, 5], [$handlerA, 10]] -- lower order first

getOption($key, $default)

tWithOptions.php:49
function getOption(string $key, mixed $default = null): mixed
$keystring
$default = nullmixedreturned if $key is not set
returnsmixed
$t->getOption('a', 'fallback'); // the current value of 'a', or 'fallback' if not set

getOptions()

tWithOptions.php:20
function getOptions(): array
returnsarrayevery option currently set
$t->getOptions(); // ['a' => 1, 'tags' => ['x']]

getSorts()

Query.php:250
function getSorts(): array
returnsarraythe sort order, field => ascending.

getVisibleFields()

Query.php:328

Resolve getFields into the actual list of field names that should be shown: with no explicit selection, every schema-declared visible property; with an explicit selection that only HIDES fields (no explicit true entries), every visible property minus those; otherwise, just the explicitly true fields.

function getVisibleFields(): array
returnsarray

hasFilters()

Query.php:136
function hasFilters(): bool
returnsboolwhether any filter condition has been added.

HasListener($handler)

statictEvent.php:109
static function HasListener(callable|object $handler): bool
$handlercallable | objecteither the exact callable passed to AddListener, or (for a [$obj, $methodName] listener registered via ConnectListeners) just the object, to check whether any of its methods are currently listening
returnsbool
UserCreated::HasListener($handler); // true if $handler is currently registeredUserCreated::HasListener($service); // true if any of $service's methods were connected via #[Listen]

isRaw()

Query.php:411

Tells if query's entities will be returned as an array (raw) instead of Entity

function isRaw(): bool
returnsbool

listOnly()

Query.php:380

Only list entities (return entity's id and properties needed in title and label)

function listOnly(): self
returnsself

listRequiredCollections($filter)

Query.php:223

List all the other required collections needed for the query

function listRequiredCollections(?MMO\core\interfaces\iFilter $filter = null): array
$filter = nullnull | iFilter[internal] use by the recursion
returnsarray[iCollection]

loopRequiredCollection($repository, $schema, $path, $_recusivePath)

Query.php:186

Recursion helper for listRequiredCollections: walks a single filter path's schema, yielding the collection behind each instance-typed segment it crosses -- including, for a computed 'label'/'title' segment (or when already recursing through one), the collections behind whatever properties that label/title template itself references.

protected function loopRequiredCollection( MMO\core\interfaces\iRepository $repository, MMO\core\interfaces\iSchema $schema, string $path, ?string $_recusivePath = null ): Generator
$repositoryiRepository
$schemaiSchema
$pathstring
$_recusivePath = nullnull | stringinternal (the accumulated path so far, once recursing).
returnsGeneratorstring $path => iCollection

pagination($limit, $offset)

Query.php:431
function pagination(?int $limit = null, ?int $offset = null): self
$limit = nullnull | int
$offset = nullnull | intif omitted entirely (not just null), $offset is left unchanged -- pass null explicitly to reset it.
returnsself

RemoveListener($handler)

statictEvent.php:91

Remove the last added handler from the listeners.

static function RemoveListener(callable $handler): boolNOTE: if you added the same handler multiple time, you need to call this function the same amount of times.
$handlercallable
returnsbooltrue if a listener was removed

Send($args)

statictEvent.php:143

Construct a new instance of this class with $args, then dispatch it to every listener.

static function Send(mixed ...$args): static
...$argsmixed
returnsstaticthe constructed (and dispatched) event instance
UserCreated::Send('Marc'); // equivalent to (new UserCreated('Marc'))->dispatch()

setFields($value)

Query.php:353

NOTE: same bug (and fix) as setSorts -- used to check $value[0] instead of $field[0], so a --prefixed field (meant to hide it) was only ever recognized when it was the very first field in the list; every other -field kept its literal - as part of the (wrong) key and was always marked visible.

function setFields(array|string $value): self
$valuearray | stringa comma-separated string, or a list of field names (optionally --prefixed to hide that field), or an already-built [field => bool] map.
returnsself

SetListenerOrder($handler, $order)

statictEvent.php:75

Change the order of an already-registered listener, whether added directly via AddListener or indirectly via ConnectListeners (which also stores its [$obj, $methodName] callables here).

static function SetListenerOrder(callable $handler, int $order): bool
$handlercallable
$orderint
returnsbooltrue if $handler was found and its order changed
UserCreated::SetListenerOrder($handler, 20); // moves $handler later in the dispatch order

setOption($key, $value)

tWithOptions.php:77

Set (or, with a null $value, remove) a single option.

function setOption(string $key, mixed $value): void
$keystring
$valuemixedif null, the option is unset entirely rather than being set to null
returnsvoid
$t->setOption('a', 1);$t->setOption('a', null); // removes 'a' from getOptions()

setOptions($opts)

tWithOptions.php:30

Replace the whole options bag.

function setOptions(array $opts): void
$optsarray
returnsvoid
$t->setOptions(['a' => 1]);

setRootOperator($operator)

Query.php:458

Change the root filter group's combining operator, wrapping the existing filters in a new group under $operator if it differs from the current one.

function setRootOperator(MMO\core\helpers\GroupOperator|string $operator): self
$operatorGroupOperator | string
returnsself

setSorts($value)

Query.php:265

NOTE: this used to check $value[0] === '-' (the LIST's own first element) inside the foreach ($value as $field) loop, instead of $field[0] (the CURRENT field being examined) -- so, except for the first field in the list, a --prefixed field (meant to sort that field descending) was never recognized as such: the leading - stayed part of the (wrong) sort key, and every field got true (ascending) regardless.

function setSorts(array|string $value): selfVerified concretely: `setSorts(['name', '-age'])` produced `['name' => true, '-age' => true]` instead of `['name' => true, 'age' => false]`. Fixed to check each $field itself.
$valuearray | stringa comma-separated string, or a list of field names (optionally --prefixed for descending), or an already-built [field => bool] map.
returnsself

sort($path, $asc)

Query.php:287

NOTE: $asc used to be typed bool (non-nullable), so the $asc === null check below could never be true -- PHP rejects passing null for a non-nullable parameter with a TypeError before the method body ever runs -- making "remove this sort" (the clear intent, matching the identical, correctly ?bool-typed pattern in the sibling field method) completely unreachable. Fixed to ?bool.

function sort(string $path, ?bool $asc = true): self
$pathstring
$asc = truenull | booltrue/false to sort ascending/descending, or null to remove any sort on $path.
returnsself

__clone()

Query.php:125

Deep-clones $filters (so mutating the clone's filters doesn't affect the original) and discards any already-run results (clearEntities).

function __clone(): void
returnsvoid

__construct($collection, $filter, $fields, $sort, $limit, $offset, $options)

Query.php:78
function __construct( MMO\core\interfaces\iCollection $collection, MMO\core\interfaces\iFilter|array|string $filter = [], array|string $fields = [], array|string $sort = [], ?int $limit = null, ?int $offset = null, array $options = [] )
$collectioniCollection
$filter = []iFilter | array | string
$fields = []array | string
$sort = []array | string
$limit = nullnull | int
$offset = nullnull | int
$options = []array