Skip to content

Commit 670e649

Browse files
committed
#14 - Document Criteria API
1 parent ad9e0fe commit 670e649

File tree

1 file changed

+146
-5
lines changed

1 file changed

+146
-5
lines changed

README.md

Lines changed: 146 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ The interface usually delivers `stdClass` objects by default. However, you can n
6565
your own data class so the data will be populated in such a class:
6666

6767
```
68-
$arr = $db->queryList('SELECT * FROM #__devtest', 'MyNamespace\MyDataClass');
69-
$obj = $db->querySingle('SELECT * FROM #__devtest WHERE uid='.$uid, 'MyNamespace\MyDataClass');
68+
$arr = $db->queryList('SELECT * FROM #__devtest', 'MyNamespace\\MyDataClass');
69+
$obj = $db->querySingle('SELECT * FROM #__devtest WHERE uid='.$uid, 'MyNamespace\\MyDataClass');
7070
```
7171

7272
## Inserting, Updating and deleting objects
@@ -144,10 +144,10 @@ However, you can tell `DAO` your specifics:
144144

145145
```
146146
// Uses a specific class for the data
147-
$dao = \TgDatabase\DAO($db, '#__users', 'MyNamespace\User`);
147+
$dao = \TgDatabase\DAO($db, '#__users', 'MyNamespace\\User`);
148148
149149
// Uses a specific class and another primary key attribute
150-
$dao = \TgDatabase\DAO($db, '#__users', 'MyNamespace\User`, 'id');
150+
$dao = \TgDatabase\DAO($db, '#__users', 'MyNamespace\\User`, 'id');
151151
```
152152

153153
`DAO` can actually handle non-numeric primary keys. The usage is not recommended though.
@@ -251,7 +251,7 @@ That way you can further abstract data access, e.g.
251251
class Users extends DAO {
252252
253253
public function __construct($database) {
254-
parent::__construct($database, '#__users', 'MyNamespace\User');
254+
parent::__construct($database, '#__users', 'MyNamespace\\User');
255255
}
256256
257257
public function findByEmail($email) {
@@ -344,6 +344,147 @@ $users = $myModel->get('users')->find();
344344

345345
Imagine, how much error-proned code you would have to write yourself!
346346

347+
# Criteria API
348+
Version 1.2 introduces a basic form of `Criteria` which gives you more freedom to express SQL conditions
349+
when searching for rows and objects. It is designed using the Hibernate ORM Criteria template. So much
350+
of the code may appear familiar to you.
351+
352+
The Criteria API was created additional to the Data Model and DAO API and enhances it. So you can still use
353+
the v1.0 way of searching objects while already starting the Criteria API. However, it is planned to
354+
replace the `queryList()` and `querySingle()` methods in `Database` as well as `count()` and
355+
`find()` methods in `DAO` by the Criteria API in next major versions. At the moment both APIs exist
356+
independently.
357+
358+
**Disclaimer:** The Criteria API cannot yet produce `GROUP BY` clauses as they are more complex to build.
359+
It will be added later.
360+
361+
## Creating a Criteria
362+
Two ways exist: Creating a `Criteria` object from the `Database` object, or alternatively from the `DAO`
363+
object:
364+
365+
```
366+
// From Database object
367+
$criteria = $database->createCriteria('#__users');
368+
369+
// From DAO object
370+
$criteria = $userDAO->createCriteria();
371+
```
372+
373+
You can define model classes (the objects returned from `SELECT` queries) and aliases when creating a `Criteria`:
374+
375+
```
376+
// From Database object
377+
$criteria = $database->createCriteria('#__users', 'MyNamespace\\User', 'a');
378+
379+
// From DAO object
380+
$criteria = $userDAO->createCriteria('a');
381+
```
382+
383+
As the DAO already knows about the model class, there is no need to mention it when creating from a `DAO`.
384+
385+
The alias is assigned to the underlying table name and will be added automatically when required in restrictions.
386+
387+
## Using Restrictions
388+
Restrictions are expressions that can be used in `WHERE` clauses (and in `JOIN` - see below). The helper
389+
class `Restrictions` helps you to create them:
390+
391+
```
392+
$expr1 = Restrictions::eq('name', 'myUsername');
393+
$expr2 = Restrictions::isNotNull('email');
394+
$criteria->add($expr1, $expr);
395+
```
396+
397+
The most common restrictions are provided: eq, ne, lt, gt, ge, le, like, isNull, isNotNull, between. You can also
398+
use restrictions between two properties:
399+
400+
```
401+
// Check for equalitity of name and email of a user.
402+
$expr = Restrictions::eq('name', 'email');
403+
```
404+
405+
And it is possible to combine restrictions with `and()` and `or()`:
406+
407+
```
408+
$expr = Restrictions::or($expr1, $expr2, $expr3);
409+
```
410+
411+
## Using Projections
412+
Basic projections - the aggregation of columns of different rows - are available:
413+
414+
```
415+
$proj = Projections::rowCount();
416+
$criteria->setProjection($proj);
417+
```
418+
419+
You will find projections for: count, distinct, sum, avg, min, max. Please notice that
420+
the returned model class is always the `stdClass` when using projections.
421+
422+
## Subcriteria and JOINs
423+
This is most likely the biggest advance in using the Criteria API. The traditional API methods
424+
were not able to use subcriteria when searching for objects depending from other tables.
425+
426+
Let's assume you want to find all books in a database whose author name start with an A.
427+
The main criteria comes from books then as it is our desired model class to be returned
428+
429+
```
430+
$criteria = $bookDAO->createCriteria('a');
431+
```
432+
433+
Next we join the authors table and add it to the main criteria using the respective restriction
434+
to join them properly:
435+
436+
```
437+
$authors = $authorDAO->createCriteria('b');
438+
$restriction = Restrictions::eq(array('a','author'), array('b','uid'));
439+
$criteria->addCriteria($authors, $restriction);
440+
```
441+
442+
And finally we apply the search condition for the author:
443+
444+
```
445+
$authors->add(Restrictions::like('name', 'A%'));
446+
```
447+
448+
## Getting the result
449+
That's the most easiest part:
450+
451+
```
452+
$criteria->list();
453+
```
454+
455+
You can set restrictions on the result:
456+
457+
```
458+
$criteria->setFirstResult(10);
459+
$criteria->setMaxResults(20);
460+
```
461+
462+
## Advantages and Limitations
463+
The Criteria API will further ease in searching object in a database and return model classes, using more
464+
complex expressions and restrictions. You will be able to dynamically apply restrictions depending on
465+
the requirements of your front-end users and your application. And you won't need the DAO once you
466+
created the `Criteria` object. It is self-contained.
467+
468+
However, some limitations exist:
469+
470+
' Criteria API supports basic use cases so far (searching objects with simple restrictions).
471+
* Only MySQL / MariaDB SQL dialect is produced (but can be extended to other dialects easily when you stick to the API).
472+
* GROUP BY clauses are not implemented
473+
* Multiple projections are not yet supported (such as `SELECT MAX(name), MIN(name) FROM #__users`) - will be extended.
474+
* Criteria API is not yet built into DAOs to make it more exchangeable. This might break the DAO API and hence will
475+
be added in one of the next major versions.
476+
* A few of the limitations may be ovecome by using the `SqlExpression` and `SqlProjection` classes:
477+
478+
```
479+
// Use a specific restriction not supported
480+
$myExpr = Restrictions::sql('my-sql-fragment');
481+
482+
// Use a specific projection not supported
483+
$myProj = Projections::sql('name, email');
484+
```
485+
486+
But feel free to raise an issue (see below) when you need some extension that is not yet supported.
487+
347488
# Contribution
348489
Report a bug, request an enhancement or pull request at the [GitHub Issue Tracker](https://github.com/technicalguru/php-database/issues).
349490

0 commit comments

Comments
 (0)