Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel 5 Repository inside service provider

Tags:

php

laravel-5

I have the following problem in my laravel 5 project. I have a service provider for form macros named MacroServiceProvider.php. Some macros should receive data from the database, I'm currently using the model and getting the results with eloquent but I want to use repositories instead, so I created my repository but I can't inject this directly to my service provider.

I want something like this:

...
public function register(MyRepoInterface $repo)
    {
        $registers = $repo->findAll();
        Form::macro...
    }
...

How can I do this?

Thanks.

like image 742
Diego Schell Fernandes Avatar asked Nov 29 '22 10:11

Diego Schell Fernandes


1 Answers

I don't think you can do what are you asking, and I think you are misunderstanding the way providers work and what they are intended for.

In providers, you usually say what are the bindings among interfaces and implementations, so that when you do dependency injection in your application code, it works. I'm pretty sure they are not intended for doing real stuff.

For what you say about your code, I imagine something like this:

  • a repository interface (MyRepoInterface) with a real implementation using Eloquent (say EloquentMyRepo)
  • a facade, say Macro, so that you can do Macro::myMacro1(), Macro::myMacro2(), etc.
  • the methods myMacro1(), myMacro2(), etc, use the repository to get some data from the db and then call some methods from the Form facade

If I'm right, then I suggest something like this.

Repository

Define the interface in the file MyRepoInterface.php with

interface MyRepoInterface 
{
    public function findAll();

    // ... your other repo methods
}

and an implementation EloquentMyRepo.php with

class EloquentMyRepo implements MyRepoInterface
{
    public function findAll()
    {
        // ... do what you need
    }
}

Facade

Define a facade file MacroFacade.php with this

use Illuminate\Support\Facades\Facade;

class MacroFacade extends Facade
{
    protected static function getFacadeAccessor()
    {
        return 'macro';
    }
}

Service class

Define your macro service class in a file MacroService.php, where you can use dependency injection and access your repository. In this class you define your myMacro1()... methods.

class MacroService
{
    protected $myRepo;

    public function __construct(MyRepoInterface $myRepo)
    {
        $this->myRepo = $myRepo;
    }

    public function myMacro1()
    {
        // access the repo
        $items = $this->myRepo->findAll();
        // ... do something with $items and finally return a string
        return Form::macro(...);
    }

    public function myMacro2($arg1, $arg2)
    {
        // ... use the parameters to do something else
    }
}

Bindings

In your Providers/AppServiceProvider.php file, go to the register() method and add

public function register()
{
    // ...
    $this->app->bind('App\MyRepoInterface', 'App\EloquentMyRepo');
    // ...
}

so that when you use MyRepoInterface in dependency injection, Laravel knows it has to use an instance of EloquentMyRepo.

Now, let's create a service provider for your macro service. Create a file Providers/MacroServiceProvider.php and put in it

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class MacroServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->bind('macro', 'App\MacroService');
    }
}

Now, when we need the facade that is registered as macro, an instance of MacroService is used.

Configuration

We finally need some changes to the configuration. Open the config/app.php file, add the new provider

...
'providers' => [
    ...
    'App\Providers\AppServiceProvider',
    ...
    'App\Providers\MacroServiceProvider',
],

(note that the MacroServiceProvider is declared after the AppServiceProvider.)

Add the alias for the facade:

'aliases' => [
    ...
    'Macro' => 'App\MacroFacade',
],

Done!

What happens

Let's suppose you call

...
Macro::myMacro1();
...

in your code. How the right method is called?

  1. Macro is an alias handled by the MacroFacade class
  2. The facade is registered in the IoC with the macro name by the getFacadeAccessor() method of MacroFacade
  3. The MacroServiceProvider registered the MacroService class as an implementation for macro
  4. An instance of MacroService must be created, but it has MyRepoInterface as dependency
  5. The AppServiceProvider said Laravel to use EloquentMyRepo when MyRepoInterfice is required
  6. So an instance of EloquentMyRepo is created and it is used to create an instance of MacroService
  7. Macro has been resolved to an instance of MacroService
  8. Laravel calls the myMacro1() method of that instance

I hope this can clarify a bit what happens.

like image 124
Marco Pallante Avatar answered Dec 04 '22 04:12

Marco Pallante