Skip to content

Instantly share code, notes, and snippets.

@skyronic
Created December 25, 2015 18:44
Show Gist options
  • Save skyronic/340135025a51be5de50a to your computer and use it in GitHub Desktop.
Save skyronic/340135025a51be5de50a to your computer and use it in GitHub Desktop.

Goal:

To build an ActiveRecord-style ORM for usage in small projects where something like Doctrine is too much or the project structure is rigid and cannot be easily incorporated with Doctrine/other ORMs.

Proposed Usage

Model:

<?php

class Book extends Model {
	public function getTable () {
		return "books";
	}
	/**
	 * This function overrides
	 * @return [type] [description]
	 */
	public function getColumns () {
		return [
			// Declare the column as a string by setting the type
			'author' => 'string',

			// Alternatively you can pass another object
			'title' => [
				'type' => 'string'
			]
		]
	}
}
?>

Configuration:

<?php

// Set the database on a single function statically. This unfortunately
// will tightly couple the model with the static ORM but I'm looking for alternate ways
// which stil maintain simplicity
ORM::setDatabase ([
	'type' => 'mysql',
	// ... 
]);
?>

Querying

This can be similar to eloquent's query system or many others. This is one of the few places I'd prefer to use reflection

<?php

ORM::query ('Book')
	->andwhere ('author', 'J.K. Rowling')
	->orWhere ('author', 'Robert Galbraith')
	->findAll ();

// or maybe even this, if it's possible without using too much 'magic' methods
Book::query ()
	->andwhere ('author', 'J.K. Rowling')
	->orWhere ('author', 'Robert Galbraith')
	->findAll ();

?>

Using Instances

<?php
$book = new Book ([
	'author' => 'John',
	'title' => "Ventriloquism for dummies"
]);
$book->save ();

// Getting and setting parameters
$book->set ('author', "Gabbo");
$author = $book->get ('author');
?>

I prefer not to use attributes or magic methods like setAuthor but other more powerful getters/setters can be built on this minimal surface-area API because:

  1. We know what columns we should work with
  2. We know the type and information about all the columns.

Hopefully I would like to keep the core API minimal and allow traits to be used to have more powerful ways to work with the data on the model.

Relationships

<?php

class Author extends Model {
	public function getTable () {
		return "authors";
	}

	public function getColumns () {
		return [
			// Declare the column as a string by setting the type
			'books' => [
				'class' => 'Book',
				'type' => Relationship::HAS_MANY,
				'foreign_key' => 'book_id',
				'local_key' => 'id' // On authors table
			],

			// Alternatively you can pass another object
			'name' => [
				'type' => 'string'
			]
		]
	}
}

class Book extends Model {
	public function getTable () {
		return "books";
	}
	public function getColumns () {
		return [
			// Declare the column as a string by setting the type
			'author' => [
				'class' => 'Author',
				'type' => Relationship::BELONGS_TO,
				'foreign_key' => 'book_id',
				'target_key' => 'id' // On authors table
			],

			// Alternatively you can pass another object
			'title' => [
				'type' => 'string'
			]
		]
	}
}

// List books by an author
// Use `getMany` so an IDE/linter can get a clear hint that it's a set of records and not a single record
$books = $author->getMany ('books');
foreach ($books as $book) {
	echo $book->get ('title');
}

// Find the author of a book
$author = $book->get ('author');
$author->get ('name');
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment