Skip to content

Latest commit

 

History

History

ORM

Darya\ORM

Darya's ORM package provides a simple and flexible Active Record implementation, including a base class for domain models that makes common tasks a breeze.

Models

Darya models are self-validating objects used to represent business entities within an application.

Darya's abstract Model implementation implements ArrayAccess, Countable, IteratorAggregate and Serializable. It is essentially a flexible set of data intended to represent an instance of a business entity.

Creating a model

use Darya\ORM\Model;

// Define a model
class Something extends Model
{
	
}

// Instantiate it with some data
$model = new Something([
	'id'   => 72,
	'name' => 'Something',
	'type' => 'A thing'
]);

Attributes

// Access its attributes using any convenient syntax
$id   = $model->id;          // 72
$name = $model['name'];      // 'Something'
$type = $model->get('type'); // 'A thing'

// Change attributes in the same way
$model->id     = 73;
$model['name'] = 'Something else';
$model->set('type', 'Another thing');

// Iterate over the attributes
foreach ($model as $key => $value) {
	// ...
}

Serializing

$serialized = serialize($model);
$attributes = $model->toArray();
$json       = $model->toJson();

Defining attribute types

class Something extends Model
{
	protected $attributes = [
		'count' => 'int',
		'data'  => 'json'
	];
}

$model = new Something;

$model->count = '1';
$count = $model->count; // 1

$model->data = ['my' => 'data']; // Stored as '{"my":"data"}'

Records

Records are supercharged models with access to persistent storage through the Darya\Storage interfaces. They implement the active record pattern, but with testability in mind.

Setting up storage

The database connection for a single record instance, or all instances of a specific type of record, can be swapped out for a different storage adapter.

use Darya\Database\Connection;
use Darya\Database\Storage;
use Darya\ORM\Record;

$databaseStorage = new Storage(
	new Connection\MySql('hostname', 'username', 'password', 'database')
);

$inMemoryStorage = new Darya\Storage\InMemory;

// Use database storage for all Records
Record::setSharedStorage($databaseStorage);

// Use in-memory storage for this type of Record
TestRecord::setSharedStorage($inMemoryStorage);

// Use in-memory storage for this instance of a User Record
$user->storage($inMemoryStorage);

// Retrieve the current storage used by the User Record
$userStorage = $user->storage();

Table names

They use the typical convention of a singular class name mapping to a plural database table name.

use Darya\ORM\Record;

class User extends Record
{
	
}

User would map to the users table.

This can of course be overridden, as can the default primary key of id.

class User extends Record
{
	protected $key = 'uid';

	protected $table = 'people';
}

Loading and saving

Records provide methods that you may be familiar with.

// Create and save a single user
$user = new User(
	'name' => 'Obi-Wan'
);
$user->save();

// Change a single user
$user = User::find(1);
$user->name = 'Chris';
$user->save();

// Load all users
$users = User::all();

// Save many users
User::saveMany($users);

Listing values

They also provide methods you may not have seen before.

// List all of the values of a given attribute
$list = User::listing('name');

// List all of the distinct values of a given attribute
$names = User::distinct('name');

Query builder

Powerful query building enables simple retrieval of specific models.

$users = User::query()
	->where('name like', '%Chris%')
	->where('parent_id', 72)
	->order('surname')
	->limit(5, 10)
	->cheers();

See the Darya\Storage and Darya\Database packages for more detail about query builders.

Relationships

Records can express relationships between themselves and others.

Defining relationships

Defining relationships is a breeze.

class Page extends Record
{
	protected $relations = [
		'author'   => ['belongs_to',      'User',   'author_id'],
		'groups'   => ['belongs_to_many', 'Group'],
		'parent'   => ['belongs_to',      'Page',   'parent_id'],
		'children' => ['has_many',        'Page',   'parent_id'],
		'sections' => ['has_many',        'Section']
	];
}

Loading and saving related records

Loading and saving them is just as easy.

$page = Page::find(1);

foreach ($page->children as $child) {
	$child->title = "$page->title - $child->title";
}

$page->save();

Saving a record will save any of its loaded related models that have had their attributes changed.

You can skip saving related models if need be.

$page->save([
	'skipRelations' => true
]);

Page::saveMany($pages, [
	'skipRelations' => true
]);

Eager loading

If you need to load the related records of many parent records, the eager loading feature will help you out.

$pages = Page::eager('children');

// Causes no storage queries; models are already loaded efficiently
foreach ($pages as $page) {
	$children = $page->children;
	// ...
}

Without eager loading (Page::all()), storage would be queried once for each parent record's children.

With eager loading, all children are loaded efficiently; one query for each relation.

An array of relations can be provided to this method to eagerly load multiple relationships.

// Load all pages and eagerly load all of their related records
$pages = Page::eager(['author', 'groups', 'parent', 'children', 'sections']);