0.1.1 2019-03-20 10:34 UTC

This package is auto-updated.

Last update: 2020-05-25 16:15:21 UTC


Latest Stable Version License Build Status Coverage Status Quality Score Total Downloads


OpenCubes is a framework-agnostic set of components that parses PSR-7 URIs into value objects:

  • Pagination
  • Filters
  • Sorting
  • Breakdown (group by)


Look at the following URL:


Here's how OpenCubes parses it:

use BenTools\OpenCubes\Component\Filter\FilterComponent;
use BenTools\OpenCubes\Component\Sort\SortComponent;
use BenTools\OpenCubes\Component\Pager\PagerComponent;
use BenTools\OpenCubes\Component\Filter\Model\CollectionFilter;
use BenTools\OpenCubes\Component\Filter\Model\RangeFilter;
use BenTools\OpenCubes\Component\Filter\Model\SimpleFilter;
use BenTools\OpenCubes\Component\Filter\Model\StringMatchFilter;
use BenTools\OpenCubes\OpenCubes;
use function BenTools\OpenCubes\current_location;

$openCubes = OpenCubes::create();
$sorting = $openCubes->getComponent(SortComponent::getName());
$filters = $openCubes->getComponent(FilterComponent::getName());
$pager = $openCubes->getComponent(
    ['default_size' => 100],
    current_location() // current_location() is the default and can be replaced by any PSR-7 Uri object

// Pagination
echo $pager->getCurrentPage(); // 3
echo $pager->getPerPage(); // 50 (it would be 100 when omiting the per_page parameter)
echo $pager->getCurrentOffset(); // 100

$pager->setNbItems(160); // Your application found 160 items
echo count($pager); // 4 pages of 50 for 160 items

// Sorting
foreach ($sorting->getAppliedSorts() as $sort) {
    echo $sort->getField(); //
    echo $sort->getDirection(); // asc

// Filters
foreach ($filters->getAppliedFilters() as $filter) {

    if ($filter instanceof RangeFilter) {
        echo $filter->getField(); // published_at
        echo $filter->getLeft(); // 2019-01-01
        echo $filter->getRight(); // 2019-01-31

    if ($filter instanceof SimpleFilter) {
        echo $filter->getField(); // category_id
        echo $filter->getValue(); // 12

    if ($filter instanceof CollectionFilter) {
        echo $filter->getField(); // tags
        print_r($filter->getValues()); // ['foo', 'bar']

    if ($filter instanceof StringMatchFilter) {
        echo $filter->getField(); // name
        echo $filter->getValue(); // 'foo'
        echo $filter->getOperator(); // StringMatchFilter::STARTS_WITH
        var_dump($filter->isNegated()); // true

Now, we can ask our persistence system (Doctrine, ElasticSearch, Solr, 3rd-party API, ...) to return books:

  • From offset 100, limit to 50 items
  • Ordered by (use your own logic to parse the field path)
  • Published between 2019-01-01 and 2019-01-31
  • In category id 12
  • Matching tag foo OR bar (AND clauses can also be set)
  • But their names MUST NOT start by foo.

Translating these value objects to query your database or API is now up to you! OpenCubes provides no bridge for the moment, but maybe in a near future.


Each component comes with a lot of customization possibilities (query parameters, default settings, ...).


Besides, you can also create your own URI parsers / builders by implementing the appropriate interfaces.


OpenCubes brings HATEOAS to your application by providing links for each component:

  • Page / PageSize links
  • Apply / remove sort link
  • Apply / remove filter
  • ...

Each native component comes with a default JSON serialization which exposes the appropriate Urls. Being JSONserializable is not mandatory for your own components, it has been designed for a ready-to-use implementation. Different serializations can be achieved through your favourite serializer (Symfony / JMS to name a few).


Dive into components


OpenCubes is still at its early stage of development and subject to breaking changes.

Feel free to contribute or report any issue.

composer require bentools/opencubes:1.0.x-dev