A minimal setup, easy to use ORM and database abstraction library

0.6.0 2016-06-03 19:18 UTC

README

Link is an ORM and database abstraction library heavily inspired by ActiveRecord and AREL. Much like ActiveRecord, Link favors convention over configuration, removing the need for lengthy mapping files and long, repetative class definitions.

Link is divided up into 3 modules meant for developer use: Connection, AST, and Entity. All 3 modules are described briefly below, as a getting started guide of sorts, but for a complete overview of how each one functions, please view each module's individual README.

Connection Module

The Connection module provides the basis for Link's other two modules. It tells the rest of Link how to turn all of it's abstracted information into something that your database will understand.

Using the Connection module is simple, and is basically the same no matter what database you'll be connecting to. In the example below, we'll be connecting to a MySQL database.

<?php
    // include autoloader

    $adapter = new DaybreakStudios\Link\Connection\Adapter\MySqlPdoAdapter('demo', '127.0.0.1', 'username', 'password');
    
    DaybreakStudios\Link\Connection\Connection::create($adapter);

Seems simple, right? Link provides adapters for many different databases, and connecting to yours is as simple as using whichever adapter suits the needs of your project.

By default, Link treats the first connection you create as your default connection. All other modules in Link use this default connection, well, by default. That way, you don't need to worry about passing around your newly created connection instance, or having to register it as a global variable.

However, should you need to use a different connection in one of the modules, each one provides their own mechanism for temporarily (or permanently) changing which connection is used. For instructions on how to do this, and for complete documentation on working with the Connection module, please view the full README.

AST Module

Sitting directly on top of the Connection module in our abstraction pyramid is the AST layer. The AST provides a mechanism for generating platform independant SQL programatically. It shares most of it's syntax and conventions with AREL, though you will notice a few changes and improvements.

A simple select statement can be written using the AST module like so:

<?php
    use DaybreakStudios\Link\AST\Table;
    
    $users = new Table('users', 'u'); // The second argument is optional, and defines the table's alias
    $sql = $users
        ->project('*')
        ->where($users['email']->eq('tyler@example.com'))
        ->getSql();
        
    // SELECT * FROM `users` `u` WHERE `u`.`email` = 'tyler@example.com';

More complex select statements can be generated by chaining together calls.

<?php
    use DaybreakStudios\Link\AST\Table;
    
    $users = new Table('users', 'u');
    $sql = $users
        ->project('*')
        ->where($users['email']->eq('tyler@example.com')->and($users['deleted']->eq(false))
        ->getSql();
        
    // SELECT * FROM `users` `u` WHERE `u`.`email` = 'tyler@exmaple.com' AND `u`.`deleted` = FALSE

All values are properly escaped using the database adapter that you defined earlier.

<?php
    use DaybreakStudios\Link\AST\Table;
    
    // Let's pretend you got this from a login for, entered by one of your users
    $userEmail = "tyler@example.com\'; drop table users;";
    
    $users = new Table('users', 'u');
    $sql = $users
        ->project('*')
        ->where($users['email']->eq($userEmail))
        ->getSql();
        
    // SELECT * FROM `users` `u` WHERE `u`.`email` = 'tyler@example.com\\\'; drop table users;'

The AST module also supports joins, calling SQL functions, and many other things. Please view the full README for the AST module's complete documentation.

Entity Module

The Entity module makes up the highest layer of abstraction in Link. It allows you to convert rows into object representations for you to manipulate programatically.

Creating a new entity is easy. Let's say you have a table, named users, which has the following fields: id, first_name, last_name, and deleted.

All you need to do is extend DaybreakStudios\Link\Entity\Entity.

<?php
    namespace Your\Project\Namespace\Entity;
    
    /**
     * @method string getFirstName()
     * @method $this  setFirstName(string $firstName)
     * @method string getLastName()
     * @method $this  setLastName(string $lastName)
     * @method bool   isDeleted()   
     * @method $this  setDeleted(bool $deleted)
     */
    use DaybreakStudios\Link\Entity\Entity;
    
    class User extends Entity {}

Yep. That's all you need to do. The PHPDoc block is completely optional, but is recommended. Most IDEs will use the @method definitions for autocompletion, and it's good to have a place that lists what methods are available. The Entity base class provides magic methods for getFieldName, setFieldName, and isFieldName.

In order to write a new entity to the database, you can use the save instance method.

<?php
    $user = new User();
    $user
        ->setFirstName('Tyler')
        ->setLastName('Example')
        ->setDeleted(false)
        ->save();
        
    printf("Created User#%d\n", $user->getId()); 

Calling save will do exactly as it's name implies: save your entity. After calling save, any changes in column values (for example, an ID being assigned by auto increment, or a column that was not populated being given a default value by the database) will immediately be accessible.

Also, you may have noticed that each of the setters in the example was called on the return value of the previous setter. The magic setter always returns the object instance, allowing you to chain your setters together.

Fetching an entity from the database is straightforward as well. You can use one of four different methods to retrieve an entity.

<?php
     // Returns a User instance, or null if no user exists with the given ID
    $user = User::find($id);
    
    // Returns a User instance matched by the given conditions, or null if none was found.
    // Will throw a DaybreakStudios\Link\Entity\Exception\NonUniqueException if more than one row matched the
    // given conditions.
    $user = User::findOneBy([
        'first_name' => 'Tyler',
    ]);
    
    // Returns an array of User objects matching the given conditions. You may optionally provide an array of order
    // by data as the second argument (formatted "column" => "direction"), and a limit and offset as the 3rd and 4th
    // arguments, respectively.
    $users = User::findBy([
        'deleted' => false,
    ]);

Please view the full README for the Entity module's complete documentation.