Lightweight ORM built on top of Nette\Database
Consider following database schema:
Firstly we'll create entity classes according to the schema above. There are two ways of defining entity properties - via @property[-read] annotation, or simply via getter and setter.
/** * @property-read int $id * @property string $name */class Tag extendsYetORM\Entity
{}/** * @property-read int $id * @property string $name * @property string $web * @property \DateTime $born */class Author extendsYetORM\Entity
{}There are some relations at the Book entity - two N:1 Author and M:N Tag relations. Every YetORM\Entity has an instance of YetORM\Record in it, which is a simple wrapper around Nette\Database\Table\ActiveRow. That means that we can access related records or column values through it.
/** * @property-read int $id * @property string $title * @property string $web * @property string $slogan */class Book extendsYetORM\Entity
{
functiongetAuthor()
{
returnnewAuthor($this->record->ref('author', 'author_id'));
}
functiongetMaintainer()
{
returnnewAuthor($this->record->ref('author', 'maintainer_id'));
}
functiongetTags()
{
$selection = $this->record->related('book_tag');
returnnewYetORM\EntityCollection($selection, 'Tag', 'tag');
}
}With $record->ref($table, $column) we're accessing related table row in table $table through column $column - pretty simple.
The M:N relation is realized with YetORM\EntityCollection instance - which is a lazy collection of entities. In this case it iterates throw all related rows from book_tag table (first argument), creates instances of Tag (second argument) and on every related book_tag table row it accesses related tag table row (third argument), which then passes to the constructor of Tag entity :-)
This sounds crazy, but it's actually simple to get used to.
With this knowledge we can now simply add some helpful methods to Author entity:
// class AuthorfunctiongetBooksWritten()
{
$selection = $this->record->related('book', 'author_id');
returnnewYetORM\EntityCollection($selection, 'Book');
}
functiongetBooksMaintained()
{
$selection = $this->record->related('book', 'maintainer_id');
returnnewYetORM\EntityCollection($selection, 'Book');
}Every repository has to have table and entity class name defined - either via @table and @entity annotaion, or via protected $table and $entity class property.
/** * @table book * @entity Book */class BookRepository extendsYetORM\Repository
{}YetORM\Repository comes with basic findAll() and findBy($criteria) methods, both returning already mentioned EntityCollection.
We can simply iterate through all books
$books = newBookRepository($connection); // $connection instanceof Nette\Database\Contextforeach ($books->findAll() as$book) { // $book instanceof Bookecho$book->title;
echo$book->getAuthor()->name;
foreach ($book->getTags() as$tag) { // $tag instanceof Tagecho$tag->name;
}
}$book = $books->getByID(123); // instanceof Book or NULL if not foundInstead of manually writing findByTitle($title) method as this
functionfindByTitle($title)
{
return$this->findBy(array(
'title' => $title,
));
}we can just call
$books->findByTitle($title); // without having the method implementedThat will return a collection of books with that exact title.
To get a single entity use the magic getBy<Property>($value) method:
$book = $books->getByIsbn('<isbn_code>'); // instanceof Book or NULL if not foundJust to have the IDE code completion along with this magic methods, we can use the @method annotation:
/** * @table book * @entity Book * @method YetORM\EntityCollection|Book[] findByTitle(string $title) * @method Book|NULL getByIsbn(string $isbn) */class BookRepository extendsYetORM\Repository
{}
/** * @property-read int $id * @property string $title * @property string $isbn */class Book extends Entity
{}IMPORTANT: When using magic
findBy<Property>()andgetBy<Property>()methods, make sure you have the property defined via@propertyannotation!
NOTE: magic
findBy<Property>()andgetBy<Property>()do not work on relational properties of type Entity.
To persist changes we simply call $repository->persist($entity).
$book->web = 'http://example.com';
$books->persist($book);And that's it!
- No identity map
- Query efficiency - the collections (resp.
YetORM\Record) use the power ofNette\Databaseefficiency - Collection operations - collections can be sorted via
$coll->orderBy($column, $dir)and limitted via$coll->limit($limit, $offset)
For more examples please see the tests.

