Installation:
composer require bosnadev/repositories:0.*
Publish the config (if needed):
php artisan vendor:publish --provider="Bosnadev\Repositories\RepositoriesServiceProvider"
Define a Repository:
Create a repository class extending Bosnadev\Repositories\Eloquent\Repository and implement the model() method:
namespace App\Repositories;
use Bosnadev\Repositories\Eloquent\Repository;
use App\Models\User;
class UserRepository extends Repository
{
public function model()
{
return User::class;
}
}
Register the Repository:
Bind the repository in a service provider (e.g., AppServiceProvider):
$this->app->bind(
\App\Repositories\UserRepository::class,
function ($app) {
return new \App\Repositories\UserRepository(new \App\Models\User);
}
);
First Use Case: Inject the repository into a controller or service and use it like Eloquent:
use App\Repositories\UserRepository;
class UserController extends Controller
{
protected $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
public function index()
{
$users = $this->userRepository->all();
return view('users.index', compact('users'));
}
}
CRUD Operations:
Use built-in methods like all(), find(), create(), update(), and delete():
$users = $userRepository->all();
$user = $userRepository->find(1);
$userRepository->create(['name' => 'John']);
Query Scoping: Chain Eloquent query methods:
$activeUsers = $userRepository->scopeQuery(function ($query) {
return $query->where('active', true);
})->all();
Dependency Injection:
Always inject repositories via constructor (not new):
public function __construct(UserRepository $userRepository) { ... }
Repository Interfaces: Define interfaces for repositories to enforce contracts:
interface UserRepositoryInterface
{
public function getByEmail(string $email);
}
Implement them in your repository:
class UserRepository extends Repository implements UserRepositoryInterface
{
public function getByEmail(string $email)
{
return $this->model->where('email', $email)->first();
}
}
Event Handling: Trigger events via repository methods:
$userRepository->create(['name' => 'John'], true); // Fires `created` event
Laravel Scout: Extend the repository for search functionality:
class UserRepository extends Repository
{
public function search($query)
{
return $this->model->search($query)->get();
}
}
API Resources: Use repositories to fetch data for API responses:
$users = $userRepository->all();
return UserResource::collection($users);
Testing: Mock repositories in tests:
$mock = Mockery::mock(UserRepository::class);
$mock->shouldReceive('find')->andReturn($user);
$this->app->instance(UserRepository::class, $mock);
Caching: Cache repository results:
$users = Cache::remember('users.all', 60, function () {
return $userRepository->all();
});
Transactions: Wrap repository operations in transactions:
DB::transaction(function () use ($userRepository) {
$userRepository->create(['name' => 'John']);
$userRepository->create(['name' => 'Jane']);
});
Model Binding:
Forgetting to implement model() will throw BadMethodCallException. Always verify:
public function model()
{
return User::class; // Must return a valid Eloquent model class
}
Lazy Loading:
Avoid eager loading in repositories to prevent N+1 queries. Use with() explicitly:
$users = $userRepository->with('posts')->find(1); // Correct
$users = $userRepository->all(); // May trigger N+1 if not careful
Mass Assignment:
Repository create()/update() uses $model->fill() by default. Override to customize:
public function create(array $attributes)
{
return parent::create($attributes, ['name', 'email']); // Whitelist
}
Soft Deletes:
Ensure your model uses SoftDeletes trait if relying on delete():
use Illuminate\Database\Eloquent\SoftDeletes;
class User extends Model
{
use SoftDeletes;
}
Service Provider Binding: Binding repositories manually can lead to singleton issues. Use Laravel's container properly:
$this->app->singleton(UserRepository::class, function ($app) {
return new UserRepository(new User);
});
Query Logging: Enable query logging to debug repository queries:
DB::enableQueryLog();
$users = $userRepository->all();
dd(DB::getQueryLog());
Model Events: Listen for model events to debug repository behavior:
User::created(function ($user) {
Log::info('User created:', ['user' => $user]);
});
Repository Methods: Override repository methods to add logging:
public function find($id)
{
Log::debug("Finding user with ID: {$id}");
return parent::find($id);
}
Custom Query Scopes: Add reusable scopes to the repository:
class UserRepository extends Repository
{
public function scopeActive($query)
{
return $query->where('active', true);
}
}
Usage:
$activeUsers = $userRepository->scopeActive()->get();
Repository Events: Dispatch events from repository methods:
public function create(array $attributes)
{
$model = parent::create($attributes);
event(new UserCreated($model));
return $model;
}
Repository Decorators: Decorate repositories to add cross-cutting concerns:
class LoggingUserRepository implements UserRepositoryInterface
{
protected $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
public function find($id)
{
Log::info("Finding user ID: {$id}");
return $this->userRepository->find($id);
}
}
Dynamic Attributes: Extend repositories to handle dynamic attributes:
public function update(array $attributes, $id)
{
$model = $this->find($id);
$model->update($attributes + ['updated_at' => now()]);
return $model;
}
Repository Factories: Use factories to create repositories with default configurations:
$userRepository = app()->makeWith(UserRepository::class, [
'model' => new User,
'cache' => true
]);
How can I help you explore Laravel packages today?