Home > OS >  Proper way to inject a service on a controller
Proper way to inject a service on a controller

Time:11-18

I am implementing the Repository Pattern (service) in a Laravel application and I have some doubts about the usage of interfaces with these services.

I have created an interface called CRUD (code bellow) to serve as a way to always keep the same names for the services that are going to implement CRUD methods.

<?php

namespace App\Interfaces;

interface CRUD
{
  public function create(array $data);
  public function update(int $id, array $data);
  public function delete(string $ids);
};

Bellow there's an example of how I call my service and the service itself, and that's where my doubts are. Usually I'll see people witing an interface for each service and demanding the controller to have injected an objet of that type. Because of that, people will have to bind a specific type (interface) to the controller. It seems redundant and thus I simply passed the service I need.

Now, is this ok or I should pass the CRUD interface to the controller in this case? Or should I even create another interface specifically for each service?

<?php

namespace App\Http\Controllers\Cms;

use App\Http\Controllers\Controller;
use App\Http\Requests\GroupRequest;
use App\Models\Group;
use App\Services\GroupsService;
use Illuminate\Http\Request;

class GroupsController extends Controller
{
  private $service;

  public function __construct(GroupsService $service)
  {
    $this->service = $service;
  }

  public function store(GroupRequest $request)
  {
    $result = $this->service->create($request->all());
    return redirect()->back()->with('response', $result);
  }

  public function update(GroupRequest $request, $id)
  {
    $result = $this->service->update($id, $request->all());
    return redirect()->back()->with('response', $result);
  }

  public function destroy($groups_id)
  {
    $result = $this->service->delete($groups_id);
    return redirect()->back()->with('response', $result);
  }
}
<?php

namespace App\Services;

use App\Models\Group;
use App\Interfaces\CRUD;
use Exception;

class GroupsService implements CRUD
{
  public function listAll()
  {
    return Group::all();
  }

  public function create(array $data)
  {
    $modules_id = array_pop($data);

    $group = Group::create($data);
    $group->modules()->attach($modules_id);

    return cms_response(trans('cms.groups.success_create'));
  }

  public function update(int $id, array $data)
  {
    try {
      $modules_ids = $data['modules'];
      unset($data['modules']);
      $group = $this->__findOrFail($id);

      $group->update($data);
      $group->modules()->sync($modules_ids);

      return cms_response(trans('cms.groups.success_update'));
    } catch (\Throwable $th) {
      return cms_response($th->getMessage(), false, 400);
    }
  }


  public function delete(string $ids)
  {
    Group::whereIn('id', json_decode($ids))->delete();
    return cms_response(trans('cms.groups.success_delete'));
  }

  private function __findOrFail(int $id)
  {
    $group = Group::find($id);
    if ($group instanceof Group) {
      return $group;
    }
    throw new Exception(trans('cms.groups.error_not_found'));
  }
}

CodePudding user response:

I did something with repo pattern in laravel 8 you might be interested:

thats how i did it:

first of all, you need to implement a provider

in this file i created the binding:

App\ProvidersRepositoryServiceProvider.php

use App\Interfaces\EventStreamRepositoryInterface;
use App\Repositories\EventStreamRepository;
use Illuminate\Support\ServiceProvider;
class RepositoryServiceProvider extends ServiceProvider
{

 public function register()
    {
        $this->app->bind(EventStreamRepositoryInterface::class, EventStreamRepository::class);
    }

}

then in file:

app\Interfaces\EventStreamRepositoryInterface.php

interface EventStreamRepositoryInterface {
    public function index();
    public function create( Request $request );
    public function delete($id);
}

in file:

App\Repositories\EventStreamRepository.php

class EventStreamRepository implements EventStreamRepositoryInterface{

public function index()
{
  return EventStream::with(['sessions'])
        ->where([ ["status", "=", 1] ] )
        ->orderBy('created_at', 'DESC')
        ->get();
}


public function create(Request $request)
{
    request()->validate([
        "data1"      => "required",
        "data2"      => "required"
    ]);

    $EventStream = EventStream::create([
        'data1'      => request("data1"),
        'data2'      => request('data2')
    ]);

    return $EventStream->id;
}

public function delete($id)
{
  return EventStream::where('id', $id)->delete();
}

}

in file:

App\Http\Controllers\EventStreamController.php

use App\Interfaces\EventStreamRepositoryInterface;
class EventStreamController extends Controller{

private EventStreamRepositoryInterface $eventStreamRepository;

public function __construct(EventStreamRepositoryInterface $eventStreamRepository)
{
    $this->eventStreamRepository = $eventStreamRepository;
}

 public function index():JsonResponse
{
  $this->eventStreamRepository->index();
}


    public function store(Request $request ):JsonResponse
    {
     $this->eventStreamRepository->create($request);
    }

 public function destroy($id):JsonResponse
    {
        $this->eventStreamRepository->delete($id);   
    }

}//class

note: i think i removed all unnecessary -validations- and -returns- in controller for better reading.

Hope it helps!!

CodePudding user response:

If you want to use Repository Design Patteren You have to create seprate Interface for each service accroing to SOLID Principle. You have to create custom service provider and register your interface and service class and then inject interface in construtor of controller. You can also follow below article. https://itnext.io/repository-design-pattern-done-right-in-laravel-d177b5fa75d4

  • Related