nilportugues / sql-repository

[PHP 7] SQL Repository implementation
http://nilportugues.com
MIT License
36 stars 3 forks source link
composer crud dbal filter orm pageable paginate php php7 sql storage

SQL Repository

PHP7 Tested Build Status SensioLabsInsight Latest Stable Version Total Downloads License Donate

SQL Repository library aims to reduce the time spent writing repositories.

Motivation for this library was the boredom of writing SQL or using query builders to do the same thing over and over again in multiple projects.

SQL Repository allows you to fetch, paginate and operate with data easily without adding overhead and following good practices.

Table of Contents

Features

Installation

Use Composer to install the package:

$ composer require nilportugues/sql-repository

Usage

Show me the code

See the /example directory. Examples for both Custom ID and AutoIncremental ID are provided.

Explanation

You're good to go.

--

Mapping

Mapping must implement the Mapping interface.

Mapping classes are used to read data from entities and save them in the storage of choice. This is done by mapping the Entities fields and specifying which fields and how are actually stored in the data storage.

For complex objects, let's say an Entity that has a Value Object, it is possible to still do one single mapping on the Entity and access the Value Object properties to get them stored.

Mappings are also used to hydrate data into it's entities again if the hydrator trait is used.

Entity class

Remember, an Entity must implement the Identity interface to work with SqlRepository. This Entity can be any class of yours.

use NilPortugues\Foundation\Domain\Model\Repository\Contracts\Identity;

class User implements Identity
{
    protected $userId;
    protected $username;
    protected $alias;
    protected $email;
    protected $registeredOn;

    /**
     * User constructor.
     *
     * @param          $userId
     * @param          $username
     * @param          $alias
     * @param          $email
     * @param \DateTime $registeredOn
     */
    public function __construct($userId, $username, $alias, $email, \DateTime $registeredOn)
    {
        $this->userId = $userId;
        $this->username = $username;
        $this->alias = $alias;
        $this->email = $email;
        $this->registeredOn = $registeredOn;
    }

   // ... your getters/setters

    public function id()
    {
        return $this->userId;
    }

    public function __toString()
    {
        return (string) $this->id();
    }
}

Mapping class

All methods from Mapping interface are mandatory.

use NilPortugues\Foundation\Domain\Model\Repository\Contracts\Mapping;

class UserMapping implements Mapping
{
    /**
     * Name of the identity field in storage.
     */
    public function identity() : string
    {
        return 'user_id';
    }

    /**
     * Returns the table name.
     */
    public function name() : string
    {
        return 'users';
    }

    /**
     * Keys are object properties without property defined in identity(). 
     * Values its SQL column equivalents.
     */
    public function map() : array
    {
        return [

            // Flat objects or objects with one value don't 
            // require dot notation.

            'userId' => 'user_id', 
            'username' => 'username',
            'alias' => 'public_username',
            'email' => 'email',

            // Notice how we are accessing date value inside
            // the \DateTime object! We use dot notation to 
            // access deep values.
            // For instance, registeredOn.timezone will be 
            // ignored because we are not mapping 

            'registeredOn.date' => 'created_at', 
        ];
    }

    /**
     * @param array $data
     * @return User
     */
    public function fromArray(array $data)
    {
        return new User(
            $data['user_id'],
            $data['username'],
            $data['public_username'],
            $data['email'],
            new \DateTime($data['created_at'])
        );
    }

    /**
     * The automatic generated strategy used will be the data-store's if set to true.
     */
    public function autoGenerateId() : bool
    {
        return true;
    }
}

Mapping the Repository

Finally, it's usage is straight-forward:

use NilPortugues\Foundation\Infrastructure\Model\Repository\Sql\SqlRepository;
use NilPortugues\Foundation\Infrastructure\Model\Repository\Sql\SqlRepositoryHydrator;

class UserRepository extends SqlRepository
{
    use SqlRepositoryHydrator;
}

$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'password');
$mapping = new UserMapping();
$repository = new UserRepository($pdo, $mapping);

Repository

The repository class implements all the methods required to interact and filter your data.

SqlRepository can handle all CRUD operations by default by extending the SqlRepository class.

If you're not into CRUD, you can also have read-only, write-only and pagination-only repositories:

Methods

Available in SqlRepository

All the methods listed under SqlWriteRepository, SqlReadRepository and SqlPageRepository.

Available in SqlWriteRepository

Available in SqlReadRepository

Available in SqlPageRepository


Data Operations

All data can be extracted by fields name, using filters, applying ordering and pages, capable of applying fields, filters and ordering criteria.

Fields

Selecting by field will make hydratation fail. Currently partial object hydratation is not supported.

Class: NilPortugues\Foundation\Domain\Model\Repository\Fields

Methods:

Filtering

Class: NilPortugues\Foundation\Domain\Model\Repository\Filter

Methods:

For must(), mustNot() and should(), the methods available are:

Pagination

Pagination is handled by two objects, Pageable that has the requirements to paginate, and Page that it's actually the page with the page data, such as page number, total number, and the data.

Pageable

Class: NilPortugues\Foundation\Domain\Model\Repository\Pageable

Methods:

Page object

Class: NilPortugues\Foundation\Domain\Model\Repository\Page

Methods:

Sorting

Class: NilPortugues\Foundation\Domain\Model\Repository\Sort

Methods:

Ordering

Sometimes you want to sort by multiple fields, this is where Order comes in play.

Class: NilPortugues\Foundation\Domain\Model\Repository\Order

Methods:

--

Quality

To run the PHPUnit tests at the command line, go to the tests directory and issue phpunit.

This library attempts to comply with PSR-1, PSR-2, PSR-4.

If you notice compliance oversights, please send a patch via Pull Request.

Contribute

Contributions to the package are always welcome!

Support

Get in touch with me using one of the following means:

Authors

License

The code base is licensed under the MIT license.