Pacuna's Blog

Usando el Patr贸n repositorio en PHP

Este patr贸n permite separar la l贸gica que entrega los datos y los mapea a la entidad desde la l贸gica de negocios que act煤a sobre el modelo. La l贸gica de negocios debe ser agn贸stica con respecto al tipo de datos que se obtiene desde la capa de fuente de datos[1]. Por ejemplo, la fuente de datos puede ser una base de datos, un web service, o como veremos en este caso, un arreglo de datos.

Supongamos que tenemos la siguiente clase entidad de Usuario:

class User
{
    protected $username;
    protected $dateOfBirth;
    protected $password;

    public function __construct($username, $dateOfBirth, $password)
    {
        $this->username = $username;
        $this->dateOfBirth = $dateOfBirth;
        $this->password = $password;
    }

    public function getUsername()
    {
        return $this->username;
    }
}

Queremos crear un repositorio para trabajar con esta entidad. En la interfaz de nuestro repositorio s贸lo tendremos 2 m茅todos, uno para agregar usuarios, y otro para verificar que un nuevo nombre de usuario sea 煤nico en la fuente de datos

interface IRepository{
    public function addUser(User $user);
    public function isUsernameUnique($username);
}

Ahora debemos crear una implementaci贸n de esta interfaz para utilizarla en nuestra l贸gica de negocios. Al utilizar una interfaz en vez de una clase concreta en nuestra aplicaci贸n, ganamos una mayor flexibilidad, ya que luego si debemos intercambiar la fuente de datos, s贸lo debemos crear una nueva implementaci贸n de la interfaz. Por ahora crearemos una clase simple que trabaje con datos en un arreglo est谩tico.

class MockRepository implements IRepository{
    private static $users = array();

    public function __construct()
    {
        self::$users[] = new User("wayne27", new Datetime("2012-07-08"), "knight");
        self::$users[] = new User("wayne27", new Datetime("2000-01-03"), "justice");
    }
    public function addUser(User $user)
    {
        self::$users[] = $user;
    }

    public function isUsernameUnique($username)
    {
        foreach (self::$users as $user) {
            if($user->getUsername() == $username) return false;
        }
        return true;
    }
}

Usar una clase de este tipo te puede servir para no preocuparte de la fuente de datos mientras construyes tu aplicaci贸n. Como la l贸gica de negocios s贸lo va a depender de una interfaz, m谩s tarde cuando tu fuente de datos ya est茅 clara, s贸lo debes crear una clase que implemente la interfaz y usar esta clase en tu l贸gica en vez de este simple mock.

Ahora en la l贸gica de tu aplicaci贸n puedes utilizar el repositorio para trabajar con los datos:

$repository = new MockRepository();
$repository->addUser(new User("nuevo", new Datetime("2000-02-02"), "pass");
$repository->isUsernameUnique("pass") //return bool=false

Inyectando las dependencias

Para hacer un buen uso del repositorio, lo mejor es que utilicemos alg煤n IoC container que tome el control de nuestra aplicaci贸n y sea capaz de inyectar la implementaci贸n correcta de la interfaz de repositorio. Supongamos que nuestra aplicaci贸n principal es ejecutada dentro de un metodo run() de una clase Main que luce de la siguiente manera

class Main
{
    protected $repository;
    public function __construct(IRepository $repository)
    {
        $this->repository = $repository;
    }

    public function run()
    {
        $user = new User("pablobloman", new Datetime("2012-02-05"), "bk999pv");
        $this->repository->addUser($user);
        var_dump($this->repository->isUsernameUnique("pabloboloman"));
    }
}

Como puedes ver, esta clase Main tiene una dependencia, pero es una interfaz, por lo que no est谩 acoplada a ninguna implementaci贸n en espec铆fico. Aqu铆 es donde se puede ver la flexibilidad de usar una interfaz. Nuestra l贸gica de negocios podr铆a estar completa y no dependemos de ninguna clase concreta. Si queremos cambiar la implementaci贸n de la interfaz, s贸lo se lo indicamos a nuestro contenedor, el cual se encagar谩 de inyectarla. Supongamos que tenemos un contenedor simple en una clase Container(). Podr铆amos ejecutar nuestra aplicaci贸n con el siguiente script

$container = new Container();
$app = $container->getInstance('Main');
$app->run();

Este peque帽o script, crea una instancia del container, luego el container crea nuestra clase principal resolviendo las dependencias, para finalmente ejecutar nuestra aplicaci贸n. Pero a煤n falta algo ,necesitamos decirle a nuestro contenedor, que la interfaz de repositorio debe ser implementada por alguna clase. Como en nuestro caso s贸lo tenemos la clase MockRepository, debemos usar esa. En los contenedores IoC, normalmente se utiliza alg煤na llamada bind() o alg煤n archivo de configuraci贸n para indicar las dependencias o las resoluciones. En mi caso estoy utilizando una implementaci贸n propia de un Container[2]. Para indicar las dependencias s贸lo debo generar un archivo con la siguiente estructura:

return array(
    'IRepository' => 'MockRepository',
);

Luego cuando el container es instanciado, carga este archivo autom谩ticamente, y registra las dependencias indicadas en el archivo.

Eso es todo! si tienes dudas comenta y tratar茅 de responderte lo antes posible.

Nota: el ejemplo de este tutorial fue tomado del libro 鈥.NET Framework 4.5 Expert Programming Cookbook鈥 y fue adaptado a PHP

[1]http://msdn.microsoft.com/en-us/library/ff649690.aspx

[2]https://github.com/pacuna/PHPContainer

View original

#php #laravel

- 1 toasts