Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Repository Laravel Package

miladimos/laravel-repository

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require miladimos/laravel-repository
    php artisan repository:install
    
    • This sets up the base configuration and publishes the necessary files.
  2. Create a Repository:

    php artisan make:repository Tag
    
    • Generates:
      • TagRepository (default implementation)
      • TagEloquentRepositoryInterface (contract)
      • TagEloquentRepository (Eloquent-specific implementation)
  3. Register the Repository:

    • Add the repository binding to app/Providers/RepositoryServiceProvider.php:
      protected $repositories = [
          TagEloquentRepositoryInterface::class => TagRepository::class,
      ];
      
    • Ensure the provider is registered in config/app.php under providers.
  4. First Use Case:

    • Inject the repository into a controller/service:
      public function __construct(TagEloquentRepositoryInterface $tagRepo) {
          $this->tagRepo = $tagRepo;
      }
      
    • Use built-in CRUD methods (e.g., find(), all(), create()):
      $tags = $this->tagRepo->all();
      $tag = $this->tagRepo->find(1);
      

Implementation Patterns

Core Workflows

  1. Dependency Injection:

    • Always inject the interface (*EloquentRepositoryInterface) into controllers/services, not the concrete class.
    • Example:
      public function store(Request $request) {
          $tag = $this->tagRepo->create($request->all());
      }
      
  2. Custom Methods:

    • Extend the interface with domain-specific methods:
      interface TagEloquentRepositoryInterface extends EloquentRepositoryInterface {
          public function findBySlug(string $slug);
          public function countActiveTags();
      }
      
    • Implement them in the repository class:
      public function findBySlug(string $slug) {
          return $this->model->where('slug', $slug)->first();
      }
      
  3. Service Layer Abstraction:

    • Use repositories in services to decouple business logic from controllers:
      class TagService {
          public function __construct(TagEloquentRepositoryInterface $tagRepo) {
              $this->tagRepo = $tagRepo;
          }
      
          public function publishTag(int $id) {
              $tag = $this->tagRepo->find($id);
              $tag->update(['is_published' => true]);
              return $tag;
          }
      }
      
  4. Pagination and Scopes:

    • Leverage Eloquent scopes for reusable queries:
      // In TagEloquentRepository
      public function scopeActive($query) {
          return $query->where('is_active', true);
      }
      
    • Use in repository methods:
      public function getActiveTags() {
          return $this->scopeQuery(function($query) {
              return $query->active();
          })->get();
      }
      
  5. Transactions:

    • Wrap repository operations in transactions for data integrity:
      public function transferTagOwnership(int $tagId, int $newOwnerId) {
          DB::transaction(function() use ($tagId, $newOwnerId) {
              $tag = $this->find($tagId);
              $tag->owner_id = $newOwnerId;
              $tag->save();
          });
      }
      

Integration Tips

  1. Testing:

    • Mock repositories in tests to isolate logic:
      $mockRepo = Mockery::mock(TagEloquentRepositoryInterface::class);
      $mockRepo->shouldReceive('find')->andReturn($tag);
      $this->app->instance(TagEloquentRepositoryInterface::class, $mockRepo);
      
  2. API Resources:

    • Pair repositories with API resources for consistent responses:
      return TagResource::collection($this->tagRepo->all());
      
  3. Event Dispatching:

    • Trigger events post-repository operations:
      public function create(array $data) {
          $model = parent::create($data);
          event(new TagCreated($model));
          return $model;
      }
      
  4. Caching:

    • Cache repository results for performance:
      public function getPopularTags() {
          return Cache::remember('popular_tags', now()->addHours(1), function() {
              return $this->scopeQuery(function($query) {
                  return $query->orderBy('views', 'desc')->limit(10);
              })->get();
          });
      }
      

Gotchas and Tips

Pitfalls

  1. Missing Provider Registration:

    • Forgetting to register RepositoryServiceProvider in config/app.php will cause ClassNotFoundException.
    • Fix: Ensure the provider is listed under providers in config/app.php.
  2. Circular Dependencies:

    • Injecting repositories into model events (e.g., Observers) can cause circular dependency issues.
    • Fix: Use the repository only in controllers/services, not models.
  3. Overusing Repositories:

    • Avoid using repositories for simple queries (e.g., User::where(...)->get()). Reserve repositories for complex or reusable logic.
    • Tip: If a method does one-off Eloquent query, consider keeping it in the controller/service.
  4. Interface Pollution:

    • Adding too many custom methods to interfaces can bloat them.
    • Tip: Group related methods into separate interfaces (e.g., TagSearchInterface, TagAnalyticsInterface).
  5. Mass Assignment Risks:

    • create()/update() methods blindly pass input to fill(). Validate input before passing to repositories.
    • Fix: Use Form Requests or validate in the service layer:
      $validated = $request->validate([...]);
      $this->tagRepo->create($validated);
      

Debugging

  1. Repository Not Bound:

    • If you get BindingResolutionException, check:
      • The interface/class names in $repositories array match exactly.
      • The provider is registered.
  2. Method Not Found:

    • Ensure custom methods are defined in both the interface and the repository class.
    • Debug: Use php artisan ide-helper:generate to regenerate IDE metadata.
  3. Eloquent Model Not Set:

    • If find() or create() fails silently, verify the repository’s $model property is set in the constructor:
      public function __construct(Tag $model) {
          $this->model = $model;
      }
      

Extension Points

  1. Custom Repository Classes:

    • Extend BaseRepository for shared functionality:
      class BaseSoftDeletesRepository extends BaseRepository {
          public function delete($id) {
              return $this->model->find($id)->delete();
          }
      }
      
  2. Dynamic Model Binding:

    • Override resolveModel() to dynamically set the model:
      protected function resolveModel($model) {
          return app()->make($model);
      }
      
  3. Repository Events:

    • Dispatch events for repository actions:
      public function create(array $attributes) {
          $model = $this->model->create($attributes);
          event(new RepositoryModelCreated($model, $this));
          return $model;
      }
      
  4. Repository Middleware:

    • Add middleware to repository methods (e.g., logging, auth):
      public function find($id) {
          $this->checkPermission('view_tag');
          return parent::find($id);
      }
      
  5. Repository Decorators:

    • Decorate repositories to add cross-cutting concerns:
      class LoggingRepositoryDecorator implements TagEloquentRepositoryInterface {
          protected $repository;
      
          public function __construct(TagEloquentRepositoryInterface $repository) {
              $this->repository = $repository;
          }
      
          public function find($id) {
              Log::info("Finding tag {$id}");
              return $this->repository->find($id);
          }
      }
      
    • Register the decorator in RepositoryServiceProvider:
      $this->app->bind(
          TagEloquentRepositoryInterface::class,
          function($app) {
              return new LoggingRepositoryDecorator(
                  $app->make(TagRepository::class)
              );
          }
      );
      

Configuration Quirks

  1. Default Repository Class:

    • The package assumes a default BaseRepository class. If missing, create one extending miladimos\Repository\Eloquent\BaseRepository.
  2. Interface Naming:

    • The generated interface name (*EloquentRepositoryInterface) is hardcoded in the make:repository command. Customize via the command’s options if needed:
      php artisan make:repository Tag --interface=TagRepositoryInterface
      
  3. Model Resolution:

    • The repository expects the model class to be passed in the constructor. If using a trait or dynamic models, override resolveModel().
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope