2017 © Pedro Peláez
 

library doctrine-extensions

Doctrine2 ORM Extensions

image

weavora/doctrine-extensions

Doctrine2 ORM Extensions

  • Friday, January 17, 2014
  • by yurytolochko
  • Repository
  • 7 Watchers
  • 14 Stars
  • 9 Installations
  • PHP
  • 0 Dependents
  • 0 Suggesters
  • 3 Forks
  • 0 Open issues
  • 2 Versions
  • 0 % Grown

The README.md

Doctrine2 Extensions Build Status

Total Downloads Latest Stable Version, (*1)

This library extends Doctrine2 base classes with some useful things., (*2)

Installation

This library may be installed using Composer or by cloning it from its GitHub repository. These options are described below., (*3)

Composer, (*4)

You can read more about Composer and its main repository on http://packagist.org. To install these doctrine extensions using Composer, first install Composer for your project using the instructions on the Packagist home page. You can then define your development dependency on doctrine-extensions using the parameters suggested below. While every effort is made to keep the master branch stable, you may prefer to use the current stable version tag instead., (*5)

{
    "require-dev": {
        "weavora/doctrine-extensions": "dev-master@dev"
    }
}

To install, you may call:, (*6)

composer.phar install

Git / GitHub, (*7)

The git repository hosts the development version in its master branch. You can install it using Composer by referencing dev-master as your preferred version in your project's composer.json file as the previous example shows., (*8)

You may also install this development version:, (*9)

git clone git://github.com/weavora/doctrine-extensions.git
cd doctrine-extensions

The above processes will install library to the doctrine-extensions folder., (*10)

ORM Extensions

Doctrine advices to use entity repositories that will contain business logic related to entities retrieval. Most probably, you will use a query builder inside the repository to build DQL. The issue is that a standard query builder has quite general API and doesn't provide such useful shortcuts like named scopes, a single method to apply custom criteria with parameters, etc., (*11)

This library is intended to fix what's missing and make your life a little bit easier., (*12)

How to organize repositories

Let's say you want to create a blog application. You'll probably create a post entity which will have references to the category, author and comments. And now you're thinking about an approach to organize your repositories., (*13)

Common issues with repositories:, (*14)

  • You have to duplicate code as soon as you have duplicated conditions
  • Even simple methods with few conditions and ordering look massive

You can solve the first issue with a custom query builder per entity. It will also hide your criteria details from the repository that doesn't really need to know that., (*15)

To solve the issue with huge and not very descriptive methods, you'll create an extension for the query builder with some helpful shortcuts to make code more readable., (*16)

An example of how PostQueryBuilder & PostRepository could look like:, (*17)

<?php

namespace Acme\BlogBundle\Entity;

use Weavora\Doctrine\ORM as ORM;

/**
 * Custom query class for Post entity
 * Contains useful criteria set for posts filtering
 */
class PostQueryBuilder extends ORM\EntityQueryBuilder
{
    public function published()
    {
        return $this->filterByColumn('Post.publishStatus', Post::STATUS_PUBLISHED);
    }

    public function recentFirst()
    {
        return $this->orderBy('Post.publishedAt', 'DESC');
    }
}

/**
 * Post entity repository
 * Contains methods for fetch posts
 */
class PostRepository extends ORM\EntityRepository
{
    /**
     * Instantiate custom query builder
     * @return PostQueryBuilder
     */
    public function filter()
    {
        return new PostQueryBuilder($this->getEntityManager(), $this);
    }

    /**
     * Find 10 recent posts
     *
     * @return Post[]
     */
    public function findRecent()
    {
        return $this
            ->filter() // use PostQueryBuilder
                ->published() // get only published posts
                ->limit(10) // get only first 10 posts
                ->recentFirst() // most recent posts should go first
            ->fetchAll(); // get posts
    }

    /**
     * Find posts by category
     *
     * @param Category $category
     * @param int $page
     * @param int $itemsPerPage
     * @return Post[]
     */
    public function findByCategory(Category $category, $page = 1, $itemsPerPage = 10)
    {
        return $this
            ->filter() // use PostQueryBuilder
                ->filterByColumn('Post.category', $category) // get only posts in the specified category
                ->paginate($page, $itemsPerPage) // get only the specified page
                ->recentFirst()  // most recent posts should go first
            ->fetchAll(); // get posts
    }

    /**
     * Count posts by author
     *
     * @param Author $author
     * @return int
     */
    public function countByAuthor(Author $author)
    {
        return $this
            ->filter() // use PostQueryBuilder
                ->select('COUNT(Post.id)') // calculate count
                ->filterByColumn('Post.author', $author) // calculate only author's posts
                ->groupBy('Post.author') // group by author
            ->fetchScalar(); // get scalar results (the first column of the first row)
    }
}

Quite simple, right?, (*18)

API / EntityQueryBuilder

getEntityAlias() : string | Get entity alias in the query, (*19)

// entity class name -> alias
// \Entity\Post -> Post
// \Acme\DemoBundle\Entity\AuthorSettings -> AuthorSettings
// \Comment -> Comment
$alias = $queryBuilder->getEntityAlias();

filterByColumn($columnName, $value, $strict = true) : EntityQueryBuilder | Compare a column with the specified value, (*20)

// SELECT * FROM Entity\Post Post WHERE Post.title = :p1, [p1 = 'Post 1']
$queryBuilder->filterByColumn('Post.title', 'Post 1');

// SELECT * FROM Entity\Post Post WHERE Post.category IN (1,2,3)
$queryBuilder->filterByColumn('Post.category', array(1,2,3));

// SELECT * FROM Entity\Post Post WHERE Post.author IS NULL
$queryBuilder->filterByColumn('Post.author', null);

// SELECT * FROM Entity\Post Post
$queryBuilder->filterByColumn('Post.author', null, false);

// SELECT * FROM Entity\Post Post WHERE Post.author = 1
$queryBuilder->filterByColumn('Post.author', 1, false);

filterByStatement($statement, $parameters = array()) : EntityQueryBuilder | Add a custom statement, (*21)

// SELECT * FROM Entity\Post Post WHERE Post.title = :title, [title = 'Post 1']
$queryBuilder->filterByStatement('Post.title = :title', ['title' => 'Post 1']);

// SELECT * FROM Entity\Post Post WHERE Post.category IN (1,2,3)
$queryBuilder->filterByColumn('Post.category IN (1,2,3)');

limit($maxResults, $offset = null) : EntityQueryBuilder | Limit results, (*22)

// SELECT * FROM Entity\Post Post LIMIT 0, 10
$queryBuilder->limit(10);

// SELECT * FROM Entity\Post Post LIMIT 15, 10
$queryBuilder->limit(10, 15);

fetchAll($parameters = array()) : EntityClass[] | Fetch a result, (*23)

// SELECT * FROM Entity\Post Post -> Post[]
$queryBuilder->fetchAll();

// SELECT * FROM Entity\Post Post LIMIT 0, 10 -> Post[]
$queryBuilder->filterByStatement('Post.title = :title')->fetchAll(['title' => 'Post 1']);

fetchOne($parameters = array()) : EntityClass | Fetch the first result, (*24)

// SELECT * FROM Entity\Post Post LIMIT 0, 1 -> Post
$queryBuilder->fetchOne();

fetchScalar($parameters = array()) : int|string|float|null | Fetch a scalar result, (*25)

// SELECT COUNT(*) FROM Entity\Post Post LIMIT 0, 1 -> int
$queryBuilder->select('COUNT(*)')->fetchScalar();

DBAL Extensions

There is only one small enhancement to DBAL classes - Connection::lockSafeUpdate that allows you to restart a query in case a transaction has been locked and failed. Maybe, it will be useful to show how to extend Doctrine connection class with custom methods., (*26)

How to configure, (*27)

# config.yml
doctrine:
    dbal:
        wrapper_class: 'Weavora\Doctrine\DBAL\Connection'

Usage example, (*28)

// Method will retry a query if it failed because of lock the first time
// You can specify the retry number as the 3rd argument
$doctrine->getConnection()->locksSafeUpdate("UPDATE posts SET category_id = :category", ['category' => 2]);

About

Stability

It's not stable yet. Please, use it at your own risk., (*29)

Requirements

  • Any flavor of PHP 5.3 or later should do
  • [optional] PHPUnit 3.5+ to execute the test suite (phpunit --version)

Submitting bugs and feature requests

Bugs and feature request are tracked on GitHub, (*30)

Author

Weavora LLC - http://weavora.com - http://twitter.com/weavora
Also see the list of contributors who have participated in this project., (*31)

License

This library is licensed under the MIT License - see the LICENSE file for details, (*32)

The Versions

17/01 2014

dev-master

9999999-dev

Doctrine2 ORM Extensions

  Sources   Download

MIT

The Requires

 

The Development Requires

orm database doctrine

21/08 2013

0.1.0

0.1.0.0

Doctrine2 ORM Extensions

  Sources   Download

MIT

The Requires

 

The Development Requires

orm database doctrine