eZ Community » Blogs » Core Development team » Call for developer feedback: the...

By

Call for developer feedback: the query builder

Friday 14 March 2014 1:06:19 pm

  • Currently 5 out of 5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

We believe that even though only bad craftsmen blame their tools, one still does a better job with the right one. A sledgehammer will get a standard nail into a plank, but it will take more preparation, more care and more time than with a good old hammer.

Now that the foundations of our repository and its API are established, we want to take a step up another layer, and focus on developer usability by making it easier to query the repository for content. But we lack the one thing you can provide us with: feedback and use-cases. But let’s explain what the situation is, and what we have in mind exactly.

Historically speaking, one aspect of eZ Publish 4 was that it made it very easy to retrieve content. You could either, from PHP, use eZContentObjectTreeNode::subtree(), or in templates, use fetch( content, list, hash(...)). It was awful in terms of concerns separation, but it did make it easy to perform those daily tasks. Version 5 was built with a strong focus on separation of concerns. We care about maintainability, scalability, and compatibility with future features and evolutions, especially for lower layers, that are gonna be with us for years. But this came with a price: usability.

 

Illustration by code

Let’s consider the following scenario: we want, from PHP, to retrieve a list of content:

  • of type ‘article’;
  • located within sections 1 or 2;
  • sorted by modification date in a descending order.
Using the public API

Using the Public API, we need to:

  • create a Query object;
  • instanciate the criterion objects we need (Query\Criterion\ContentTypeIdentifier andQuery\Criterion\SectionId), with their respective arguments, and instruct the query to use a boolean AND on those;
  • Create a SortClause object , and provide it with a value from the Query class
use eZ\Publish\API\Repository\Values\Content\Query;
 
$q = new Query();
$q->criterion = new Query\Criterion\LogicalAnd(
    array(
        new Query\Criterion\ContentTypeIdentifier( 'article' ),
        new Query\Criterion\SectionId( array( 1, 2 ) )
    )
);
$q->sortClauses = array(
    new Query\SortClause\DateModified( Query::SORT_DESC )
);

It is quite verbose, and requires knowledge of namespaces and class hierarchy. Custom namespaces, which we intend to support soon, complexify this even further. The code is predictable, and quite clear, but we don't believe it qualifies as usable on a daily basis for business critical, common operations.

Ideally: a real fluent API

Martin Fowler wrote, in 2005, about fluent interfaces (I really recommend this article). Most developers will think “chaining calls” when you mention those. But chaining is just syntaxic sugar. A fluent interface first and foremost matches the domain language. SQL is a good example of a fluent language, at least in its essence. In our case, the eZ Publish domain, within which a location, a contentTypeIdentifier or sectionId have a specific and known meaning. If you know the domain, you can use the API, and if you read an API call, you will know what it means.

It could look like this:

use eZ\Publish\API\Repository\QueryBuilder;
 
$queryBuilder = new QueryBuilder();
$queryBuilder
   ->contentTypeIdentifier()->eq( 'article' )
   ->sectionId()->in( 1, 2 )
   ->wasCreated()->after( 'last year' )
   ->sortBy()
       ->dateModified()->descending()
$query = $queryBuilder->getQuery();

It isn't much shorter (well, a bit), but every word counts, and has a clear and explicit meaning. Furthermore, the API is documented enough to offer contextual completion on those calls. The operators available for an identifier or an operation will be different, depending on each criterion. For instance, while a date would have methods such as "before()" or "after()", a textual value would suggest "match()", or "beginsWith()". If a method is suggested, we expect it to work, and we expect to be provided with every method that applies in the context.

Your turn now

So, would a real fluent API make your life easier in regards to querying content ? Should we go a completely different direction ? I, for one, am convinced that it is a safe way to go, and have a plan when it comes to making it hold onto its promises. But there are many questions left, and I know that most of you have something to say about that. Did you face particular difficulties that we need to take into consideration ? Do you remember a content query that was a nightmare to write, or do you have one you are very proud of ? Let us know, and we can, together, work out the best solution to your problems.

You can comment on this blog post (ideally) and/or fill out this short survey. Pings on Twitter or Google+ are also fine. Crows are acceptable.

Proudly Developed with from