Installation:
composer require rinvex/laravel-repositories
Publish the config (if needed):
php artisan vendor:publish --provider="Rinvex\Repositories\RepositoriesServiceProvider"
Define a Repository:
Create a model (e.g., User) and its corresponding repository interface:
// app/Repositories/Contracts/UserRepositoryInterface.php
namespace App\Repositories\Contracts;
use Rinvex\Repositories\Contracts\RepositoryInterface;
interface UserRepositoryInterface extends RepositoryInterface
{
public function findByEmail(string $email);
}
Implement the Repository:
// app/Repositories/Eloquent/UserRepository.php
namespace App\Repositories\Eloquent;
use App\Repositories\Contracts\UserRepositoryInterface;
use Rinvex\Repositories\Eloquent\EloquentRepository;
class UserRepository extends EloquentRepository implements UserRepositoryInterface
{
public function findByEmail(string $email)
{
return $this->scopeQuery(function ($query) use ($email) {
return $query->where('email', $email);
})->first();
}
}
Bind the Repository:
In a service provider (e.g., AppServiceProvider):
$this->app->bind(
\App\Repositories\Contracts\UserRepositoryInterface::class,
\App\Repositories\Eloquent\UserRepository::class
);
First Use Case: Inject and use the repository in a controller:
// app/Http/Controllers/UserController.php
use App\Repositories\Contracts\UserRepositoryInterface;
class UserController extends Controller
{
protected $userRepository;
public function __construct(UserRepositoryInterface $userRepository)
{
$this->userRepository = $userRepository;
}
public function show($email)
{
$user = $this->userRepository->findByEmail($email);
return view('user.show', compact('user'));
}
}
CRUD Operations:
Leverage built-in methods like all(), find(), create(), update(), and delete():
$users = $this->userRepository->all();
$user = $this->userRepository->find(1);
$this->userRepository->create(['name' => 'John']);
Custom Scopes:
Use scopeQuery() to add reusable query constraints:
public function scopeActive($query)
{
return $this->scopeQuery(function ($query) {
return $query->where('active', true);
});
}
Usage:
$activeUsers = $this->userRepository->scopeActive()->get();
Caching:
Enable granular caching via config (config/repositories.php):
'cache' => [
'enabled' => true,
'default' => 'file',
'stores' => [
'file' => [
'driver' => 'file',
'path' => storage_path('framework/cache/repositories'),
],
],
],
Cache methods automatically (e.g., find(), all()).
Transactions: Wrap operations in transactions:
$this->userRepository->transaction(function () {
$user = $this->userRepository->create(['name' => 'Alice']);
$profile = $this->profileRepository->create(['user_id' => $user->id]);
});
Service Layer: Use repositories in a service layer to decouple business logic from controllers:
// app/Services/UserService.php
class UserService
{
protected $userRepository;
public function __construct(UserRepositoryInterface $userRepository)
{
$this->userRepository = $userRepository;
}
public function register(array $data)
{
return $this->userRepository->create($data);
}
}
API Resources: Combine with Laravel's API Resources for clean JSON responses:
// app/Http/Resources/UserResource.php
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
];
}
Usage:
return new UserResource($this->userRepository->find(1));
Events: Trigger events post-CRUD operations:
$this->userRepository->created(function ($user) {
event(new UserRegistered($user));
});
Abandoned Package:
spatie/laravel-query-builder or archtechx/laravel-repository.Caching Overhead:
cache()->forget() or repository()->flushCache() to clear caches manually when needed.$this->userRepository->flushCache();
Model Binding:
repository() helper or manually bind interfaces in the service container.$this->app->bind(\App\Repositories\Contracts\UserRepositoryInterface::class,
\App\Repositories\Eloquent\UserRepository::class);
Laravel Version Mismatch:
dev-develop branch targets Laravel 5.5+. For newer versions, expect potential compatibility issues (e.g., query builder syntax, dependency conflicts).Performance with Large Datasets:
all() or get() for large datasets, as it may load excessive data into memory.$users = $this->userRepository->paginate(10);
Query Logging: Enable Laravel's query logging to debug repository queries:
DB::enableQueryLog();
$this->userRepository->all();
dd(DB::getQueryLog());
Cache Debugging: Check cache hits/misses by inspecting the cache store:
$cache = Cache::store('file');
$cache->get('repository:User:all');
Repository Events: Listen for repository events to debug lifecycle hooks:
event(new Creating($model));
event(new Created($model));
Custom Repository Classes:
Extend Rinvex\Repositories\Eloquent\EloquentRepository to add shared logic:
class BaseRepository extends EloquentRepository
{
public function softDelete($id)
{
return $this->find($id)->delete();
}
}
Dynamic Scopes: Use traits to add dynamic scopes across repositories:
trait Searchable
{
public function scopeSearch($query, $term)
{
return $this->scopeQuery(function ($query) use ($term) {
return $query->where('name', 'like', "%{$term}%");
});
}
}
Repository Decorators: Decorate repositories to add cross-cutting concerns (e.g., logging, auditing):
class LoggingRepositoryDecorator implements UserRepositoryInterface
{
protected $repository;
public function __construct(UserRepositoryInterface $repository)
{
$this->repository = $repository;
}
public function find($id)
{
Log::info("Finding user with ID: {$id}");
return $this->repository->find($id);
}
}
Bind the decorator in the service container:
$this->app->bind(
UserRepositoryInterface::class,
function ($app) {
return new LoggingRepositoryDecorator(
$app->make(\App\Repositories\Eloquent\UserRepository::class)
);
}
);
Testing: Mock repositories in tests for isolation:
$mock = Mockery::mock(UserRepositoryInterface::class);
$mock->shouldReceive('find')->andReturn($user);
$this->app->instance(UserRepositoryInterface::class, $mock);
How can I help you explore Laravel packages today?