Search code examples
laraveloopdesign-patternslaravel-5.7

How to change the using of the pattern repository loaded using interfaces for initializing the model? Laravel, Laracom


Good day.

A store was created based on https://github.com/Laracommerce/laracom on Laravel.

In the process, it was noticed that, along with pulling up the implementation for the interface with a call like:

use App\Products\Repositories\Interfaces\ProductRepositoryInterface;

the binding of which is declared in RepositoryServiceProvider (app \ Providers \ RepositoryServiceProvider.php),

direct calls like use App\Shop\Products\Repositories\ProductRepository are used;

(e.g. here app/Shop/Orders/Repositories/OrderRepository.php)

You can find several similar examples in the code, and most often a direct address is required to invoke $repositoryWithModel = new Repository($modelObject).

I did not find a definite way out of this situation, I ask the advice of those who came across an example of quality implementation.


Solution

  • The implementation of your ProductRepository expects a Product as constructor parameter. A respository should not do that. Instead if a repository has to handle a product model, it should be passed as a parameter to a function.

    For example this:

        /**
         * @param Brand $brand
         */
        public function saveBrand(Brand $brand)
        {
            $this->model->brand()->associate($brand);
        }
    

    Can be rewritten to:

        /**
         * @param Product $product
         * @param Brand $brand
         */
        public function saveBrand(Product $product, Brand $brand)
        {
            $product->brand()->associate($brand);
        }
    

    If you remove the Product parameter from the constructor, then you can use the repository without creating it using the new keyword every time:

    class BrandController extends Controller {
    
       public function __construct(ProductRepositoryInterface $repository) {
           $this->repository = $repository;
       }
    
       public function linkBrandToProduct(Request $request): void {
          $product = $this->repository->findProductById($request->productId);
          $brand = $this->repository->findBrandById($request->brandId);
    
          $this->repository->saveBrand($product, $brand);
       }
    }