Parable Documentation

ORM Overview#

Parable's ORM uses an ActiveRecord pattern-like system, where every model corresponds to a database table, but a minimalist Repository implementation helps deal with loading existing models.

Basic Usage#

The first thing to do is to define a model class that extends the base Model class. A good example of this is the provided /app/Model/User.php from the default structure.

You define the table name and default primary key in $tableName and $tableKey, and the columns on the table itself as public properties.

<?php
namespace Model;

class User extends \Parable\ORM\Model
{
    /** @var string */
    protected $tableName = 'user';
    
    /** @var string */
    protected $tableKey  = 'id';
    
    /** @var string */
    public $username;
    
    /** @var string */
    public $password;§
    
    /** @var string */
    public $email;
}

If you include a $created_at public property, the ORM will automatically set that when inserting a record. If you include an $updated_at property, every update on it will update that field as well.

Create a new User and save it:

<?php
$user = \Model\User::create();

$user->username = "Testing Person";
$user->password = password_hash("actual-pass-here", PASSWORD_DEFAULT);
$user->email    = "555-email@test.test";

$user->save(); // will return bool on success or fail

After saving a new instance of a model, the $tableKey will be set based on the return value from the database.

Repositories#

You can choose to do it directly with the main Repository class or with extending classes.

Directly:

<?php
$userRepo = \Parable\ORM\Repository::createForModelName(\Model\User::class);

// array of model instances
$all = $userRepo->getAll();

// array of model instances
$some = $userRepo->getByCondition("email", "LIKE", "person@%");

// single model instance
$one = $userRepo->getById(1337);

Extending:

<?php
class UserRepository extends \Parable\ORM\Repository
{
    public function getUsersWithEmailAddresses()
    {
        return $this->getByCondition("email", "is not null");
    }
    
    public function getUsersWithoutEmailAddresses()
    {
        return $this->getByCondition("email", "is null");
    }
}

This would allow you to use all the basic Repository logic, but also offer far more fine-grained methods. Using extending classes can make it far clearer what you're working with, and can even make it easier, i.e. by implementing a create() method that calls \Parable\ORM\Repository::createForModelName() so you can instantly get a specific Repository.

Another way is by adding the repositories you need to the constructor to let DI set up the Repositories you'll need.

Working with Models#

A Model instance is responsible for saving (whether it's to insert or update, for example) and deleting.

To save a model (new or updated), simply call $model->save(). It'll return a bool value of whether it succeeded or not. To delete a model, call $model->delete(), and again it'll return a bool.

It's also possible to get a Query instance populated with the model's tablename and primary key.

<?php
$query = $model->createQuery();
$query->where(
    $query->buildAndSet([$model->getTableKey(), '=', $model->id])
);

echo $query;

This would output:

SELECT * FROM `model` WHERE (`model`.`id` = '1');

What's used to add many types of conditions are ConditionSets, a system to easily and reliably build nested AND/OR condition clauses.

Edit on GitHub