Comunidad de diseño web y desarrollo en internet online

POO: Inyección de dependencias en Laravel (IV)

Esta es la cuarta parte de la mini serie de inyección de dependencias en Laravel, lee la primera, la segunda y la tercera antes de continuar.

Necesitas conocimientos básicos de Laravel y POO para hacer este tutorial.


Vimos en capítulos anteriores que la inyección de dependencias, pese a su nombre complicado, es realmente un concepto simple que permite escribir objetos “desacoplados”, es decir, que no sean dependientes uno del otro.

La inyección de dependencias nos permite diseñar ORMs que en vez de estar atado a un solo motor de DB, reciban como parámetro clases MySQL o Postgresql o incluso de MongoDB que funcionen siempre que cumplan con una “interfaz”.

El “contenedor de inyección de dependencias” es como una máquina ensambladora que conecta una parte con otra y hace que todo el sistema funcione.

También vimos que manipular las dependencias de nuestro sistema puede ser difícil, por eso el contenedor de Laravel es inteligente, y aún así sigue siendo simple! Para demostrarlo les creé un demo.

Bien ahora dejémonos de demos y vamos a usar el contenedor real de Laravel!

Para enseñarles cómo usar la inyección de dependencias en Laravel necesito 3 pasos:

Primero crearemos una clase de ejemplo y luego la integraremos con el contenedor de Laravel.

Paso 1: Clase Alert de ejemplo


Yo creé para uds. una mini versión de mi clase Alert que es un helper para enviar mensajes del controlador a las vistas, en mi caso uso los estilos de Bootstrap pero es adaptable.



Código :

<?php namespace Components;

use Illuminate\Session\Store as Session;
use Illuminate\View\Environment as View;

class Alert {

    const SESSION_NAME = 'AlertMessages';

    public function __construct(Session $session, View $view)
    {
        $this->session = $session;
        $this->view = $view;
    }

    public function message($message, $type)
    {
        $messages = $this->session->get(static::SESSION_NAME, array());
        $messages[] = compact('message', 'type');
        $this->session->flash(static::SESSION_NAME, $messages);
    }

    public function render($template = 'alert')
    {
        $messages = $this->session->get(static::SESSION_NAME, null);

        if ($messages != null)
        {
            $this->session->flash(static::SESSION_NAME, null);
            return $this->view->make($template)->with('messages', $messages);
        }

        return "";
    }

}


Esta clase tiene dos métodos: message graba mensajes y render los muestra.

La clase usa la Sesión de Laravel para guardar mensajes entre una petición y otra y la clase de Vista para los templates.

Para usarla:

1. Dentro de app creen las carpetas y el archivo: app/library/Components/Alert.php allí copien y peguen el código de arriba.
2. Abran composer.json y en “autoload” -> “classmap” agreguen "app/library/Components" ejemplo:

Código :

   "autoload": {
      "classmap": [
                                    ……...
                                    "app/library/Components"


3. Ejecuten en la consola “php artisan dump-autoload”.
4. En la carpeta app/views creen un archivo llamado alert.blade.php y copien lo siguiente:

app/views/alert.blade.php

Código :

@foreach ($messages as $msg)
<div class="alert alert-block alert-{{ $msg['type'] }} fade in">
    <button type="button" class="close" data-dismiss="alert">&times;</button>
    <p><strong>{{ $msg['message'] }}</strong></p>
</div>
@endforeach


Esta es la plantilla que usará la clase Alert por defecto.

Veamos un ejemplo de cómo usarla, en un método cualquiera de un controlador agreguen esto:

Código :

        $alert = new Components\Alert(App::make('session.store'), App::make('view'));
        $alert->message('Laravel es genial', 'info');


Asignen la variable $alert a la vista:

Código :

        return View::make('admin/users/list')->with('alert', $alert);


Y en cualquier Vista simplemente:

Código :

{{ $alert->render() }}


Si usan una plantilla que implemente Bootstrap verán un bonito mensaje en azul que dirá “Laravel es genial”.

Con esto terminamos el paso 1.

Paso 2: Usar el contenedor de inyección de dependencias de Laravel


El código anterior se enfrenta al menos a dos inconvenientes.

1. Usarlo es complicado, es decir instanciar la clase, es demasiado código y difícil de recordar:

Código :

$alert = new Components\Alert(App::make('session.store'), App::make('view'));


De hecho podría ser peor, pero yo tomé un atajo y usé el contenedor de Laravel (alias “App”) para traerme la clase de session y la clase de view:

Código :

App::make('session.store')


De lo contrario haría falta instanciar esas clases y cada una de sus dependencias, lo cual podría volverse fácilmente unas 10 líneas de código.

2. La clase y variable $alert debe pasarse siempre a la vista, de lo contrario obtendremos un error de que la variable no está definida.

Con el contenedor de Laravel podemos resolver ambos problemas muy fácilmente:

Usando los ServiceProviders

Laravel le llama Service Providers a las clases que almacenan la configuración de la inyección de dependencias, son como los ensambladores de la aplicación.

1. Creen un archivo nuevo en app/library/Components/AlertProvider.php y peguen este código:

Código :

<?php namespace Components;

use Illuminate\Support\ServiceProvider;
use Illuminate\Foundation\AliasLoader;

class AlertProvider extends ServiceProvider {

    public function register()
    {
        $this->registerAlert();
    }

    public function registerAlert()
    {
        $this->app->bind('alert', function($app)
        {
            return new Alert($app['session.store'], $app['view']);
        });
    }

}


2. Ejecuten nuevamente php artisan dump-autoload.

3. Vamos a decirle a Laravel que queremos incluir este ServiceProvider en nuestra App, vamos a app/config/app.php y en el array “providers” agregaremos 'Components\AlertProvider' a la lista:

Código :

   'providers' => array(
                        …………
                        ………...
                        'Components\AlertProvider'
   ),


4. ¡Ya podemos instanciar nuestra clase Alert con el contenedor de dependencias! Es decir:

Código :

        $alert = App::make('alert');
        $alert->message('Laravel es genial', 'info');


Paso 3: Uso de los Facades en Laravel

Aún App::make(‘alert’) se ve algo extraño, no? A pesar de que es más limpio, no sería mejor tener algo como Route::get ? De hecho “Route::get” es lo que Taylor Otwell llamó facades.

Creemos el nuestro:

1. Creen el archivo app/library/Components/AlertFacade.php

Y coloquen lo siguiente:

Código :

<?php namespace Components;

use Illuminate\Support\Facades\Facade;

class AlertFacade extends Facade {

    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor() { return 'alert'; }

}


2. Luego regresemos a nuestro ServiceProvider y vamos a crear un Alias para el Facade:

Código :

<?php namespace Components;

use Illuminate\Support\ServiceProvider;
use Illuminate\Foundation\AliasLoader;

class AlertProvider extends ServiceProvider {

    public function register()
    {
        $this->registerAlert();
        $this->setAliases();
    }

    public function registerAlert()
    {
        $this->app->bind('alert', function($app)
        {
            return new Alert($app['session.store'], $app['view']);
        });
    }

    public function setAliases()
    {
        $this->app->booting(function ()
        {
            $loader = AliasLoader::getInstance();
            // Facades
            $loader->alias('Alert', 'Components\AlertFacade');
        });
    }

}


3. No olviden ejecutar el dump-autoload.

Una vez hecho estos tres pasos en nuestro controlador ya podemos usar el Alert así:

Código :

Alert::message('Laravel es genial', 'info');


Noten que NO estamos instanciando la clase, por lo tanto tampoco necesitamos la variable $alert, en la vista queda así:

Código :

{{ Alert::render() }}


Más limpio y bonito imposible.

Sin embargo noten que tampoco estamos haciendo uso de clases estáticas, lo cual es una mala práctica casi siempre, lo que ocurre es que el Facade se encarga de interactuar con el contenedor de inyección de dependencias de Laravel que a su vez instancia y almacena la clase por nosotros.

Es decir, cada vez que haz hecho Route::get o View::make en realidad estabas trabajando con inyección de dependencias sin darte cuenta!.

Les recomiendo seguir la documentación de Laravel IoC Container y Facades para aprender más de estos geniales conceptos.

Con esto concluyo la mini serie de inyección de dependecias, espero que les haya gustado.

Sígueme en Twitter y aprende más sobre programación

¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.

Publica tu comentario

o puedes...

¿Estás registrado en Cristalab y quieres
publicar tu URL y avatar?

¿No estás registrado aún pero quieres hacerlo antes de publicar tu comentario?

Registrate