https://github.com/mibk/leanmapperquery
Concept of Query Object for LeanMapper
https://github.com/mibk/leanmapperquery
database leanmapper php php-library
Last synced: 12 months ago
JSON representation
Concept of Query Object for LeanMapper
- Host: GitHub
- URL: https://github.com/mibk/leanmapperquery
- Owner: mibk
- License: mit
- Created: 2013-12-29T11:58:20.000Z (over 12 years ago)
- Default Branch: master
- Last Pushed: 2025-04-30T13:53:02.000Z (about 1 year ago)
- Last Synced: 2025-05-31T02:43:40.386Z (about 1 year ago)
- Topics: database, leanmapper, php, php-library
- Language: PHP
- Homepage:
- Size: 169 KB
- Stars: 10
- Watchers: 5
- Forks: 7
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
Lean Mapper Query
=================
Lean Mapper Query is a concept of a *query object* for
[Lean Mapper library](https://github.com/Tharos/LeanMapper) which helps to build complex
queries using automatic joins (*idea taken from [NotORM library](https://www.notorm.com/)*).
Look at the [suggested base classes](https://gist.github.com/mibk/9410266). For Czech
documentation have a look at the [wiki](https://github.com/mibk/LeanMapperQuery/wiki).
Features
--------
- behaves as a `SQL` preprocessor, hence most SQL expressions are available
- automatic joins using the *dot notation* (`@book.tags.name`)
- ability to query repositories or entities
- support for implicit filters
Installation
------------
It can be installed via [Composer](https://getcomposer.org/download).
```
composer require mbohuslavek/leanmapper-query
```
What does it do?
----------------
Suppose we have the following repositories:
```php
class BaseRepository extends LeanMapper\Repository
{
public function find(Query $query)
{
$this->createEntities($query
->applyQuery($this->createFluent(), $this->mapper)
->fetchAll()
);
}
}
class BookRepository extends BaseRepository
{
}
```
and the following entities:
```php
/**
* @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*:
```php
$query = new LeanMapperQuery\Query;
$query->where('@author.name', 'Karel');
```
Now, if we want to get all books whose author's name is Karel, we have to do this:
```php
$bookRepository = new BookRepository(...);
$books = $bookRepository->find($query);
```
The database query will look like this:
```sql
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:
```php
$query->where('DATE(@pubdate) > %d', '1998-01-01');
$books = $bookRepository->find($query);
```
which changes the database query into the following:
```sql
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.
```php
class BookQuery extends LeanMapperQuery\Query
{
public function restrictAvailable()
{
$this->where('@available', true)
->orderBy('@author.name');
return $this;
}
}
/////////
$query = new BookQuery;
$query->restrictAvailable();
$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:
```php
class BaseEntity extends LeanMapperQuery\Entity
{
protected static $magicMethodsPrefixes = ['find'];
protected function find($field, Query $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:
```php
$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:
```sql
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](https://gist.github.com/mibk/9410266)*. It makes
the following possible.
```php
$books = $bookRepository->query()
->where('@author.name', 'Karel')
->where('DATE(@pubdate) > ?', '1998-01-01')
->find();
// or...
$tags = $book->queryTags()
->where('@name !=', 'ebook')
->find();
```
License
-------
Copyright (c) 2013 Michal Bohuslávek
Licensed under the MIT license.