Skip to content
Concept of Query Object for LeanMapper
PHP Makefile
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.

Lean Mapper Query

Lean Mapper Query is a concept of a query object for Lean Mapper library which helps to build complex queries using automatic joins (idea taken from NotORM library). Look at the suggested base classes. For Czech documentation have a look at the wiki.


  • behaves as a SQL preprocessor, hence most SQL expressions are available
  • automatic joins using the dot notation (
  • ability to query repositories or entities
  • support for implicit filters


It can be installed via Composer.

composer require mbohuslavek/leanmapper-query:@dev

What does it do?

Suppose we have the following repositories:

class BaseRepository extends LeanMapper\Repository
	public function find(IQuery $query)
			->applyQuery($this->createFluent(), $this->mapper)

class BookRepository extends BaseRepository

and the following entities:

 * @property int    $id
 * @property string $name
class Tag extends LeanMapper\Entity

 * @property int      $id
 * @property Author   $author m:hasOne
 * @property Tag[]    $tags m:hasMany
 * @property DateTime $pubdate
 * @property string   $name
 * @property bool     $available
class Book extends LeanMapper\Entity

 * @property int    $id
 * @property string $name
 * @property Book[] $books m:belongsToMany
class Author extends LeanMapper\Entity

We build a query:

$query = new LeanMapperQuery\Query;
$query->where('', 'Karel');

Now, if we want to get all books whose author's name is Karel, we have to do this:

$bookRepository = new BookRepository(...);
$books = $bookRepository->find($query);

The database query will look like this:

SELECT [book].*
FROM [book]
LEFT JOIN [author] ON [book].[author_id] = [author].[id]
WHERE ([author].[name] = 'Karel')

You can see it performs automatic joins via the dot notation. It supports all relationship types known to Lean Mapper.

It is very easy to use SQL functions. We can update query like this:

$query->where('DATE(@pubdate) > %d', '1998-01-01');
$books = $bookRepository->find($query);

which changes the database query into the following:

SELECT [book].*
FROM [book]
LEFT JOIN [author] ON [book].[author_id] = [author].[id]
WHERE ([author].[name] = 'Karel') AND (DATE([book].[pubdate]) > '1998-01-01')

Don't repeat yourself

You can extend the Query class and define your own methods.

class BookQuery extends LeanMapperQuery\Query
	public function restrictAvailable()
		$this->where('@available', TRUE)
		return $this;


$query = new BookQuery;
$books = $this->bookRepository->find($query);

Querying entities

It is also possible to query an entity property (currently only those properties with BelongsToMany or HasMany relationships). Let's make the BaseEntity class:

class BaseEntity extends LeanMapperQuery\Entity
	protected static $magicMethodsPrefixes = array('find');

	protected function find($field, IQuery $query)
		$entities = $this->queryProperty($field, $query);
		return $this->entityFactory->createCollection($entities);

 * ...
class Book extends BaseEntity

Note that BaseEntity must extend LeanMapperQuery\Entity to make the following possible.

We have defined the find method as protected because by specifying the method name in the $magicMethodsPrefixes property, you can query entities like this:

$book; // previously fetched instance of an entity from a repository
$query = new LeanMapper\Query;
$query->where('@name !=', 'ebook');
$tags = $book->findTags($query);

The magic method findTags will eventually call your protected method find with 'tags' as the 1st argument.

The resulting database query looks like this:

SELECT [tag].*
FROM [tag]
WHERE [tag].[id] IN (1, 2) AND ([tag].[name] != 'ebook')

The first condition in the where clause, [tag].[id] IN (1, 2), is taken from the entity traversing (tags are queried against this particular book entity's own tags).

What else you can do?

If we slightly modify BaseRepository and BaseEntity, we can simplify working with query objects. To achieve this look at the suggested base classes. It makes the following possible.

$books = $bookRepository->query()
	->where('', 'Karel')
	->where('DATE(@pubdate) > ?', '1998-01-01')

// or...

$tags = $book->queryTags()
	->where('@name !=', 'ebook')


Copyright (c) 2013 Michal Bohuslávek

Licensed under the MIT license.

You can’t perform that action at this time.