1. Code
  2. PHP
  3. Laravel

Cómo registrar y utilizar los proveedores de servicios Laravel

Si alguna vez te has encontrado con el framework de Laravel, es muy poco probable que no hayas oído hablar de contenedores de servicios y proveedores de servicios. De hecho, son la columna vertebral del framework de Laravel y hacen todo el trabajo pesado cuando ejecutas una instancia de cualquier aplicación de Laravel.
Scroll to top

Spanish (Español) translation by CYC (you can also view the original English article)

Si alguna vez te has encontrado con el framework de Laravel, es muy poco probable que no hayas oído hablar de contenedores de servicios y proveedores de servicios. De hecho, son la columna vertebral del framework de Laravel y hacen todo el trabajo pesado cuando ejecutas una instancia de cualquier aplicación de Laravel.

En este artículo, veremos de qué se trata el contenedor de servicios y, a continuación, hablaremos en detalle del proveedor del servicio. En el transcurso de este artículo, también demostraré cómo crear un proveedor de servicios personalizado en Laravel. Una vez que creas un proveedor de servicios, también debes registrarlo en la aplicación Laravel para poder usarlo, por lo que también lo revisaremos.

Hay dos métodos importantes, arranque y registro, que tu proveedor de servicios puede implementar, y en el último segmento de este artículo discutiremos estos dos métodos a fondo.

Antes de sumergirnos en la discusión de un proveedor de servicios, intentaré presentar el contenedor de servicios, ya que se usará mucho en la implementación de tu proveedor de servicios.

Entender los contenedores de servicio y proveedores de servicios

¿Qué es un contenedor de servicio?

En términos simples, podríamos decir que el contenedor de servicio en Laravel es una caja que contiene enlaces de varios componentes, y se sirven según sea necesario a lo largo de la aplicación.

En palabras de la documentación oficial de Laravel:

El contenedor de servicios de Laravel es una poderosa herramienta para administrar dependencias de clases y realizar inyecciones de dependencia.

Por lo tanto, siempre que necesites inyectar cualquier componente o servicio incorporado, puedes ingresar la sugerencia en tu constructor o método, y se inyectará automáticamente desde el contenedor de servicios, ya que contiene todo lo que necesitas. ¿No es genial? Te ahorra instanciar manualmente los componentes y, por lo tanto, evita un acoplamiento estricto en tu código.

Echemos un vistazo a un ejemplo rápido para entenderlo.

1
Class SomeClass
2
{
3
    public function __construct(FooBar $foobarObject)
4
    {
5
        // use $foobarObject object

6
    }
7
}

Como puedes ver, SomeClass necesita una instancia de FooBar para crear una instancia. Entonces, básicamente, tienes una dependencia que necesita ser inyectada. Laravel lo hace automáticamente al examinar el contenedor de servicios e inyectar la dependencia adecuada.

Y si te preguntas cómo sabe Laravel qué componentes o servicios incluir en el contenedor de servicios, la respuesta es el proveedor del servicio. Es el proveedor de servicios quien le dice a Laravel que vincule varios componentes en el contenedor de servicios. De hecho, se llama enlaces de contenedores de servicio, y debe hacerlo a través del proveedor de servicios.

Por lo tanto, es el proveedor del servicio el que registra todos los enlaces de contenedor de servicio y se realiza a través del método de registro de la implementación del proveedor de servicios.

Eso debería traer otra pregunta sobre la mesa: ¿cómo sabe Laravel sobre varios proveedores de servicios? ¿Acabas de decir algo? ¡Acabo de escuchar a alguien decir eso, Laravel debería resolver eso también automáticamente! Oh chico, eso es demasiado pedir: Laravel es un framework no un superhombre, ¿no? Bromas aparte, eso es algo que debes informar a Laravel explícitamente.

Continúa y observa los contenidos del archivo config/app.php. Encontrarás una entrada de un array que enumera todos los proveedores de servicios que se cargarán durante el arranque de la aplicación Laravel.

1
'providers' => [
2
 
3
        /*

4
         * Laravel Framework Service Providers...

5
         */
6
        Illuminate\Auth\AuthServiceProvider::class,
7
        Illuminate\Broadcasting\BroadcastServiceProvider::class,
8
        Illuminate\Bus\BusServiceProvider::class,
9
        Illuminate\Cache\CacheServiceProvider::class,
10
        Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
11
        Illuminate\Cookie\CookieServiceProvider::class,
12
        Illuminate\Database\DatabaseServiceProvider::class,
13
        Illuminate\Encryption\EncryptionServiceProvider::class,
14
        Illuminate\Filesystem\FilesystemServiceProvider::class,
15
        Illuminate\Foundation\Providers\FoundationServiceProvider::class,
16
        Illuminate\Hashing\HashServiceProvider::class,
17
        Illuminate\Mail\MailServiceProvider::class,
18
        Illuminate\Notifications\NotificationServiceProvider::class,
19
        Illuminate\Pagination\PaginationServiceProvider::class,
20
        Illuminate\Pipeline\PipelineServiceProvider::class,
21
        Illuminate\Queue\QueueServiceProvider::class,
22
        Illuminate\Redis\RedisServiceProvider::class,
23
        Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
24
        Illuminate\Session\SessionServiceProvider::class,
25
        Illuminate\Translation\TranslationServiceProvider::class,
26
        Illuminate\Validation\ValidationServiceProvider::class,
27
        Illuminate\View\ViewServiceProvider::class,
28
 
29
        /*

30
         * Package Service Providers...

31
         */
32
        Laravel\Tinker\TinkerServiceProvider::class,
33
 
34
        /*

35
         * Application Service Providers...

36
         */
37
        App\Providers\AppServiceProvider::class,
38
        App\Providers\AuthServiceProvider::class,
39
        // App\Providers\BroadcastServiceProvider::class,

40
        App\Providers\EventServiceProvider::class,
41
        App\Providers\RouteServiceProvider::class,
42
],

Entonces, ese era el contenedor de servicio a tu disposición. A partir de la siguiente sección, nos centraremos en el proveedor de servicios, ¡que es el tema principal de este artículo!

¿Qué es un proveedor de servicios?

Si el contenedor de servicios es algo que te permite definir enlaces e inyectar dependencias, entonces el proveedor de servicios es el lugar donde sucede.

Echemos un vistazo rápido a uno de los principales proveedores de servicios para entender qué hace. Abre el archivo vender/laravel/framework/src/Illuminate/Cache/CacheServiceProvider.php

1
public function register()
2
{
3
    $this->app->singleton('cache', function ($app) {
4
        return new CacheManager($app);
5
    });
6
 
7
    $this->app->singleton('cache.store', function ($app) {
8
        return $app['cache']->driver();
9
    });
10
 
11
    $this->app->singleton('memcached.connector', function () {
12
        return new MemcachedConnector;
13
    });
14
}

Lo importante a tener en cuenta aquí es el método de registro, que te permite definir enlaces de contenedor de servicio. Como puedes ver, hay tres enlaces para los servicios en caché, cache.store y memcached.connector.

Básicamente, estamos informando a Laravel que siempre que sea necesario resolver una entrada de caché, debe devolver la instancia de CacheManager. Así que solo estamos agregando un tipo de mapeo en el contenedor de servicio al que se puede acceder a través de $this->app.

Esta es la forma correcta de agregar cualquier servicio a un contenedor de servicio Laravel. ¡Eso también te permite darte cuenta de una imagen más amplia sobre cómo Laravel pasa por el método de registro de todos los proveedores de servicios y rellena el contenedor de servicios! Y como mencionamos anteriormente, recoge la lista de proveedores de servicios del archivo config/app.php.

Y esa es la historia del proveedor de servicios. En la siguiente sección, analizaremos cómo crear un proveedor de servicios personalizado para que puedas registrar tus servicios personalizados en el contenedor de servicios de Laravel.

Crea tu proveedor de servicio personalizado

Laravel ya viene con una herramienta práctica en la línea de comandos, artisan, que te permite crear un código de plantilla para que no tengas que crearlo desde cero. Continúa y ve a la línea de comandos y ejecuta el siguiente comando en la raíz de la aplicación para crear un proveedor de servicios personalizado.

1
$php artisan make:provider EnvatoCustomServiceProvider

2
Provider created successfully.

Y eso debería crear el archivo EnvatoCustomServiceProvider.php bajo el directorio de la aplicación app/Providers. Abre el archivo para ver lo que contiene.

1
<?php
2
namespace App\Providers;
3
 
4
use Illuminate\Support\ServiceProvider;
5
 
6
class EnvatoCustomServiceProvider extends ServiceProvider
7
{
8
    /**

9
     * Bootstrap the application services.

10
     *

11
     * @return void

12
     */
13
    public function boot()
14
    {
15
        //

16
    }
17
 
18
    /**

19
     * Register the application services.

20
     *

21
     * @return void

22
     */
23
    public function register()
24
    {
25
        //

26
    }
27
}

Como mencionamos anteriormente, hay dos métodos, arranque y registro, con los cuales tratarás la mayor parte del tiempo cuando trabajes con tu proveedor de servicios personalizado.

El método register es el lugar donde defines todos los enlaces de contenedor de servicio personalizado. Por otro lado, el método boot es el lugar donde puedes consumir servicios ya registrados a través del método de registro. En el último segmento de este artículo, discutiremos estos dos métodos en detalle, ya que estudiaremos algunos casos de uso prácticos para comprender el uso de ambos métodos.

Registrar tu proveedor de servicio personalizado

Entonces has creado tu proveedor de servicios personalizado. ¡Eso es genial! A continuación, debes informar a Laravel acerca de tu proveedor de servicios personalizado para que pueda cargarlo junto con otros proveedores de servicios durante el arranque.

Para registrar tu proveedor de servicios, solo necesitas agregar una entrada a la matriz de proveedores de servicios en el archivo config/app.php.

1
'providers' => [
2
 
3
        /*

4
         * Laravel Framework Service Providers...

5
         */
6
        Illuminate\Auth\AuthServiceProvider::class,
7
        Illuminate\Broadcasting\BroadcastServiceProvider::class,
8
        Illuminate\Bus\BusServiceProvider::class,
9
        Illuminate\Cache\CacheServiceProvider::class,
10
        Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
11
        Illuminate\Cookie\CookieServiceProvider::class,
12
        Illuminate\Database\DatabaseServiceProvider::class,
13
        Illuminate\Encryption\EncryptionServiceProvider::class,
14
        Illuminate\Filesystem\FilesystemServiceProvider::class,
15
        Illuminate\Foundation\Providers\FoundationServiceProvider::class,
16
        Illuminate\Hashing\HashServiceProvider::class,
17
        Illuminate\Mail\MailServiceProvider::class,
18
        Illuminate\Notifications\NotificationServiceProvider::class,
19
        Illuminate\Pagination\PaginationServiceProvider::class,
20
        Illuminate\Pipeline\PipelineServiceProvider::class,
21
        Illuminate\Queue\QueueServiceProvider::class,
22
        Illuminate\Redis\RedisServiceProvider::class,
23
        Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
24
        Illuminate\Session\SessionServiceProvider::class,
25
        Illuminate\Translation\TranslationServiceProvider::class,
26
        Illuminate\Validation\ValidationServiceProvider::class,
27
        Illuminate\View\ViewServiceProvider::class,
28
 
29
        /*

30
         * Package Service Providers...

31
         */
32
        Laravel\Tinker\TinkerServiceProvider::class,
33
 
34
        /*

35
         * Application Service Providers...

36
         */
37
        App\Providers\AppServiceProvider::class,
38
        App\Providers\AuthServiceProvider::class,
39
        // App\Providers\BroadcastServiceProvider::class,

40
        App\Providers\EventServiceProvider::class,
41
        App\Providers\RouteServiceProvider::class,
42
        App\Providers\EnvatoCustomServiceProvider::class,
43
],

¡Y eso es! ¡Haz registrado tu proveedor de servicios con el esquema de cosas de Laravel! Pero el proveedor de servicios que hemos creado es casi una plantilla en blanco y no sirve para nada en este momento. En la siguiente sección, veremos un par de ejemplos prácticos para ver qué puedes hacer con los métodos de registro y arranque.

Ir a través de los métodos de registro y arranque

Para empezar, revisaremos el método de registro para entender cómo podrías usarlo. Abre el archivo del proveedor de servicios app/Providers/EnvatoCustomServiceProvider.php que se creó anteriormente y reemplaza el código existente con lo siguiente.

1
<?php
2
namespace App\Providers;
3
 
4
use Illuminate\Support\ServiceProvider;
5
use App\Library\Services\DemoOne;
6
 
7
class EnvatoCustomServiceProvider extends ServiceProvider
8
{
9
    public function boot()
10
    {
11
    }
12
 
13
    public function register()
14
    {
15
        $this->app->bind('App\Library\Services\DemoOne', function ($app) {
16
          return new DemoOne();
17
        });
18
    }
19
}

Hay dos cosas importantes a tener en cuenta aquí:

  • Importamos App\Library\Services\DemoOne para que podamos usarlo. La clase DemoOne aún no se ha creado, pero lo haremos en un momento.
  • En el método de registro, hemos utilizado el método de vinculación bind del contenedor de servicio para agregar nuestro enlace de contenedor de servicio. Por lo tanto, siempre que la dependencia App\Library\Services\DemoOne necesite resolverse, llamará a la función de cierre y creará la instancia y devolverá el objeto App\Library\Services\DemoOne.

Así que solo necesitas crear el archivo app/Library/Services/DemoOne.php para que esto funcione.

1
<?php
2
namespace App\Library\Services;
3
 
4
class DemoOne
5
{
6
    public function doSomethingUseful()
7
    {
8
      return 'Output from DemoOne';
9
    }
10
}

Y aquí está el código en algún lugar de tu controlador donde se inyectará la dependencia.

1
<?php
2
namespace App\Http\Controllers;
3
 
4
use App\Http\Controllers\Controller;
5
use App\Library\Services\DemoOne;
6
 
7
class TestController extends Controller
8
{
9
    public function index(DemoOne $customServiceInstance)
10
    {
11
        echo $customServiceInstance->doSomethingUseful();
12
    }
13
}

Ese es un ejemplo muy simple de vincular una clase. De hecho, en el ejemplo anterior, no hay necesidad de crear un proveedor de servicios e implementar el método de registro como nosotros lo hicimos, ya que Laravel puede resolverlo automáticamente utilizando la reflexión.

Una nota muy importante de la documentación de Laravel:

No es necesario vincular clases al contenedor si no dependen de ninguna interfaz. El contenedor no necesita instrucciones sobre cómo construir estos objetos, ya que puede resolver automáticamente estos objetos mediante el reflejo.

Por otro lado, hubiera sido realmente útil si hubieras vinculado una interfaz a una determinada implementación. Veamos un ejemplo para entenderlo.

Vamos a crear una interfaz muy simple en app/Library/Services/Contracts/CustomServiceInterface.php.

1
<?php
2
// app/Library/Services/Contracts/CustomServiceInterface.php

3
namespace App\Library\Services\Contracts;
4
 
5
Interface CustomServiceInterface
6
{
7
    public function doSomethingUseful();
8
}

A continuación, creemos dos implementaciones concretas de esta interfaz. Básicamente, solo necesitamos crear dos clases que extiendan la interfaz CustomServiceInterface.

Crea la clase DemoOne en app/Library/Services/DemoOne.php

1
<?php
2
// app/Library/Services/DemoOne.php

3
namespace App\Library\Services;
4
 
5
use App\Library\Services\Contracts\CustomServiceInterface;
6
 
7
class DemoOne implements CustomServiceInterface
8
{
9
    public function doSomethingUseful()
10
    {
11
      return 'Output from DemoOne';
12
    }
13
}

Del mismo modo, DemoTwo entra en app/Library/Services/DemoTwo.php.

1
<?php
2
// app/Library/Services/DemoTwo.php

3
namespace App\Library\Services;
4
 
5
use App\Library\Services\Contracts\CustomServiceInterface;
6
 
7
class DemoTwo implements CustomServiceInterface
8
{
9
    public function doSomethingUseful()
10
    {
11
      return 'Output from DemoTwo';
12
    }
13
}

Ahora, en lugar de vincular una clase, vincularemos una interfaz. Revisa EnvatoCustomServiceProvider.php y cambia el código como se muestra a continuación.

1
<?php
2
namespace App\Providers;
3
 
4
use Illuminate\Support\ServiceProvider;
5
use App\Library\Services\DemoOne;
6
 
7
class EnvatoCustomServiceProvider extends ServiceProvider
8
{
9
    public function boot()
10
    {
11
    }
12
 
13
    public function register()
14
    {
15
        $this->app->bind('App\Library\Services\Contracts\CustomServiceInterface', function ($app) {
16
          return new DemoOne();
17
        });
18
    }
19
}

En este caso, hemos vinculado la interfaz App\Library\Services\Contracts\CustomServiceInterface a la implementación de DemoOne. Por lo tanto, siempre que necesite resolverse la dependencia App\Library\Services\Contracts\CustomServiceInterface, crea una instancia y devuelve el objeto App\Library\Services\DemoOne. Ahora tiene más sentido, ¿no?

Revisemos rápidamente el código del controlador también.

1
<?php
2
namespace App\Http\Controllers;
3
 
4
use App\Http\Controllers\Controller;
5
use App\Library\Services\Contracts\CustomServiceInterface;
6
 
7
class TestController extends Controller
8
{
9
    public function index(CustomServiceInterface $customServiceInstance)
10
    {
11
        echo $customServiceInstance->doSomethingUseful();
12
    }
13
}

Como ya habrás adivinado, $customServiceInstance ¡debería ser la instancia de App\Library\Services\DemoOne! La belleza de este enfoque es que puedes intercambiar la implementación DemoOne con la otra fácilmente.

Digamos que quieres usar la implementación DemoTwo en lugar de DemoOne. En ese caso, solo necesitas realizar los siguientes cambios en el proveedor de servicios EnvatoCustomServiceProvider.php.

Encuentra la siguiente línea:

1
use App\Library\Services\DemoOne;

Y cámbiala por:

1
use App\Library\Services\DemoTwo;

Del mismo modo, encuentra esta:

1
return new DemoOne();

Esto debería ser reemplazado por:

1
return new DemoTwo();

Se puede usar el mismo enfoque si deseas reemplazar cualquier implementación central con la tuya. Y no solo es el método de vinculación que podrías usar para las conexiones de contenedor de servicio; el contenedor de servicio Laravel proporciona varias formas de vincularse en el contenedor de servicio. Consulta la documentación oficial de Laravel para obtener la referencia completa.

El siguiente candidato es el método boot, que puedes usar para ampliar la funcionalidad básica de Laravel. En este método, puedes acceder a todos los servicios que se registraron utilizando el método de registro del proveedor del servicio. En la mayoría de los casos, deseas registrar tus "listeners" de eventos con este método, que se activará cuando ocurra algo.

Echemos un vistazo a algunos ejemplos que requieren la implementación del método de arranque.

Deseas agregar tu propio validador de campos en un formulario personalizado a Laravel.

1
public function boot()
2
{
3
    Validator::extend('my_custom_validator', function ($attribute, $value, $parameters, $validator) {
4
        // validation logic goes here...

5
    });
6
}

Si deseas registrar una vista composer, ¡es el lugar perfecto para hacerlo! De hecho, podríamos decir que el método de arranque se usa frecuentemente para agregar vistas de composer.

1
public function boot()
2
{
3
    View::composer(
4
        'demo', 'App\Http\ViewComposers\DemoComposer'
5
    );
6
}

Por supuesto, en primer lugar, deseas importar una fachada Illuminate\Support\Facades\View en tu proveedor de servicios.

¡En el mismo territorio, también puedes compartir los datos en múltiples vistas!

1
public function boot()
2
{
3
    View::share('key', 'value');
4
}

También se puede usar para definir enlaces de modelo explícitos.

1
public function boot()
2
{
3
    parent::boot();
4
 
5
    Route::model('user', App\User::class);
6
}

Estos fueron algunos ejemplos para demostrar el uso del método de arranque. Mientras más entres en Laravel, ¡más razones encontrarás para implementarlo!

Y con eso, hemos llegado al final de este artículo. Espero que hayas disfrutado de los temas que se discutieron a lo largo de este artículo.

Conclusión

Fue la plática de los proveedores de servicios la atracción central de este artículo, aunque comenzamos nuestro artículo con el contenedor de servicios, ya que era un ingrediente importante para entender al proveedor del servicio.

Después de eso, desarrollamos un proveedor de servicios personalizado, y en la segunda mitad del artículo revisamos un par de ejemplos prácticos.

Para aquellos de ustedes que recién están comenzando con Laravel o buscando ampliar su conocimiento, sitio o aplicación con extensiones, tenemos una variedad de cosas que pueden estudiar en Envato Market.

Si tienes alguna pregunta o comentario, simplemente hazme saber utilizando el siguiente feed.