What are the design standards for Serviceprovider and Servicecontainer used in Laravel and Symfony?

Asked

Viewed 1,308 times

13

In frameworks Laravel 4 ou 5 and Symfony, I realize that there are two classes that are essential for the operation of the whole system: Servicecontainer and Serviceprovider.

It seems to be a way for you to store instances of classes in a container with their dependencies already solved, or else a Closure, that loads the definitions of those dependencies (I think these are the "services"). Thus, by calling a particular service (which is in the container), we are calling in a more simplified way the instance of the desired class.

I will give an example of what I mean, but this example there is no Serviceprovider (service provider), but only the use of service container:

Service Container

 class UrlGenerator
 {
      public function __construct(Request $request)
      {}
 }

 class Request{
       public function __construct(Header $header){}
 }

 class Header{}

Here comes the definition of instances in the container.

 $app->bind('header', function () { 

    return new Header;
 });

 $app->bind('request', function ($app)
 {
      return new Request($app->getService('header'));
 });

 $app->bind('url', function ($app)
 {
      return new UrlGenerator($app->getService('request'));
 });

So if we needed to use the class UrlGenerator, instead of always having to pass an instance of Request, we could do that:

 $app->getService('url')->getRoot();

Service Provider

In the other case, we have the ServiceProvider, which could do the following:

class UrlGeneratorProvider extends ServiceProvider
{
     public function register()
     {
           $this->app->bind('url', function ($app) { /** **/});
     }
}

Then in that case, you’d be called by ServiceContainer

$app->setService(new UrlGeneratorProvider);

In that case, I understand that the UrlGeneratorProvider, passes the definition necessary to create the service, simply through the method register.

I found this pattern interesting and I’d like to know what their names are. Because in some frameworks the classes responsible for containing all services are called Application, Container or ServiceContainer. In the case of "service providers" the names are always these, most of the time.

1 answer

8


I developed, at the end of last year (2015), my TCC on a comparison between Frameworks Codeigniter and Laravel 5, and on the use of design standards in their developments. So I studied a lot about the Design Patterns used in Laravel. And one of the things I liked most about Laravel is just this part of Serviceprovider.

You explained the operation of the Serviceprovider and of Servicecontainer. These mechanisms are in accordance with the INVERSION OF CONTROL (Ioc). This standard is used to decrease class coupling.

See below a simple class that records a sale of a product and then should record a log.

public class VendaDeProduto { 
    public function vendeProduto($produto) { 
        //Todo o código para a venda do produto... 
        $log = new Log("Arquivo.txt"); 
        $log->grava($produto); 
    } 
}

Note that the classes Saleproduct is responsible for instantiating Log classes. But what happens when I need to change the log file name to "Arquivolog.txt"?

You will need to edit all classes that instantiate the Log class and perform this change. For this reason it is necessary to remove from the class Saleproduct the control of this instantiation.

There are some ways to accomplish the Inversion of Control, one of them is using the Dependency injection. See the code below:

public class VendaDeProduto { 
    private $log; 
    public function vendaDeProduto(Log $logVenda) { 
        $this->log = $logVenda; 
    } 
    public function vendeProduto($produto) { 
        //Todo o código para a venda do produto... 
        $log->grava($produto); 
    } 
}

The class Saleproduct needs the class Log to create a Log but in this code the Salesproduct class received an instance of the Log class! That is, now she no longer cares about creating the Log class and simply uses it.

Now is the best thing about Laravél (in my opinion), Serviceprovider. See below one of the many ways to implement the Log service:

class LogProvider extends ServiceProvider
{
     public function register()
     {
           $this->app->bind('Log', function ($app) { 
                return new LogFile("ArquivoLog.txt");
           });
     }
}

Note that actually when we use the service Log, we are actually using a class instance Logfile. If by chance, I want to stop recording the log in text file and start recording in a database, I can simply change the implementation of my service by going to instantiate the class Logembanco.

$this->app->bind('Log', function ($app) { 
    return new LogEmBanco("MySQL");
});

And like a magic, all my logs start to be written to the Mysql database, without changing any other class.

Summarizing your question, research on INVERSION OF CONTROL and ADDICTION INJECTION.

From a read on this link, here is everything I wrote and a little more.

http://www.devmedia.com.br/inversao-de-controle-x-injecao-de-dependencia/18763

Browser other questions tagged

You are not signed in. Login or sign up in order to post.