rikta / php-query
Fluently query a repository for data
Requires
- php: ^7.4|^8.0
- ext-json: *
- rikta/repository: dev-main
- rikta/timed-loop: ^1.0
- rikta/value-path: ^0.1.0
Requires (Dev)
README
Fluently Query a repository or array for items that match certain criteria and arrange the results in a particular order.
Like a low-budget php version of an ORM-library where budget wasn't even enough for a database and we have to be happy with in-session-memory.
Contrary to the proper db-based libraries this one works on anything that can be represented inside a key-value store or array.
Just wrap a collection of something (Arrays, Files in a Directory, a decoded CSV-File) into a rikta/repository and fire a query on it.
You could also store the query on a variable and then call it for different repositories, or use it as a configurable getter.
(For your convenience you can also just pass an array; it will be converted into an ArrayRepository
automatically)
Installation
composer require rikta/php-query
No config, no dependency-injection, nothing. Plug&Play!
Usage
- Create a new query object, e.g.
$query = new Query();
- Add some operations, e.g.
$query->not()->isNull()->sort()->limit(10)
- Get your result-object, e.g.
$result = $query->getResults()
- Get your items from the result, e.g.
return $result->toArray()
(with keys) orreturn $result->getItems()
(without keys)
Example
The examples
-directory contains several examples
(those are part of a testsuite and therefore guaranteed to work)
One of the rather verbose ones, it uses a list of 100 popular classical books as input and finds the three biggest english books after 1900 mapped to their authors
$query = (new \Rikta\PhpQuery\Query()) ->onPathValue('.year')->greaterThanOrEqual(1900) // only books after 1900 ->onPathValue('.language')->identical('English') // only books in english ->onPathValue('.pages')->sort(static fn ($a, $b) => $b <=> $a) // sort by pages, in descending order ->limit(3) // limit the results to three ->onPathValue('.title')->mapToKey() // set the key to $value['title'] ->onPathValue('.author')->mapToValue() // set the value to $value['author'] ->sort(); $results = $query ->getResultsFor(new \Rikta\PhpQuery\Examples\_Data\BookDataRepository()) ->toArray(); \PHPUnit\Framework\assertEquals([ 'The Golden Notebook' => 'Doris Lessing', 'Tales' => 'Edgar Allan Poe', 'Invisible Man' => 'Ralph Ellison', ], $results);
Operations
Operations are invokable objects (= callables with a state, you could say) that
- get all the data they need at construction time, maybe even other operations
- get an array of items at invocation
- do something with the passed $items
- return it for the next operation to modify
Operations are divided into multiple categories. Every operation will retain the initial keys in its return (unless specifically instructed otherwise).
QueryOperation Categories:
Filter
Filters the keys/values, e.g. against an array of a callable
Check _FilterOperationMethodsInterface for an up-to-date overview of all implemented filter-methods
Examples:
- only show keys from provided array
- only show value which is bigger than two
Juggling
Modifies the arrays order and bounds, but not the values themselves (Except maybe discarding them)
Check _JugglingOperationMethodsInterface for an up-to-date overview of all implemented filter-methods
Examples:
- sort in ascending order of value
- sort in descending order of keys
- limit to 20 results
Modification
Modifies another Operation
Check _ModificationOperationMethodsInterface for an up-to-date overview of all implemented filter-methods
Examples:
- inverting a filter (keep what would have been thrown away and vice versa)
- comparing a subvalue instead of a value
Replacement
Replaces the keys/values, e.g. with a value from a path or with the result of a callable
Check _ReplacementOperationMethodsInterface for an up-to-date overview of all implemented filter-methods
Examples:
- replace the returned values with $value['something'][0]
- replace the keys in the result with each valued $value['id']
Why the name?
The initial name was just "Query", but during development I ended up with Namespaces like
Rikta\Query\Query\Query
, so I renamed the project to mitigate this redundancy a bit.
I'm open for any suggestions on a better name ;)