artesaos/warehouse
Warehouse V2 is a Laravel repository-pattern demo/package that centralizes queries and business rules while still returning Eloquent models and Collections. Use it as a ready-to-use repository layer without giving up Eloquent’s practicality.
Installation:
composer require artesaos/warehouse 2.x-dev
Register the service provider in config/app.php (only if using Fractal):
'providers' => [
Artesaos\Warehouse\WarehouseServiceProvider::class,
],
Create a Repository:
Define a repository class extending BaseRepository or AbstractCrudRepository:
namespace App\Repositories;
use App\Models\User;
use Artesaos\Warehouse\BaseRepository;
class UserRepository extends BaseRepository
{
protected $modelClass = User::class;
}
First Use Case: Inject the repository into a controller/service and use its methods:
public function index(UserRepository $userRepo)
{
$users = $userRepo->getAll(10); // Paginated list
return view('users.index', compact('users'));
}
BaseRepository: For basic CRUD operations.AbstractCrudRepository: For full CRUD methods (if available in later versions).newQuery(): Access the Eloquent query builder for custom queries.doQuery(): Execute queries with pagination/take logic.Basic CRUD:
// Get all (paginated)
$users = $userRepo->getAll(15);
// Find by ID (throws ModelNotFoundException if not found)
$user = $userRepo->findByID(1);
// List specific columns
$names = $userRepo->lists('name');
Custom Queries:
Override newQuery() or use doQuery():
public function activeUsers()
{
return $this->doQuery($this->newQuery()->where('active', true));
}
Dependency Injection: Register repositories in Laravel's IoC container (optional but recommended):
$this->app->bind(
UserRepository::class,
function ($app) {
return new UserRepository(new User());
}
);
Integration with Services: Use repositories in services to encapsulate business logic:
class UserService {
public function __construct(private UserRepository $userRepo) {}
public function getActiveUsers()
{
return $this->userRepo->activeUsers();
}
}
Repository Interfaces: Define interfaces for repositories to enforce contracts:
interface UserRepositoryInterface {
public function getAll($take = 15, $paginate = true);
public function findByID($id, $fail = true);
}
Query Scopes: Use Eloquent scopes in repositories:
class UserRepository extends BaseRepository {
protected function newQuery()
{
return parent::newQuery()->with(['posts']);
}
}
Event Handling:
Dispatch events in repositories (e.g., after save):
public function save(array $data)
{
$model = $this->modelClass::create($data);
event(new UserCreated($model));
return $model;
}
Archived Package:
laravel-repository or spatie/laravel-repository.No Full CRUD in Base:
BaseRepository lacks full CRUD methods (e.g., create, update, delete). Extend AbstractCrudRepository if available (check for v3+ updates).Fractal Dependency:
Eloquent Overhead:
No Query Builder:
scopeWhere() or scopeFilter()). Implement manually:
public function scopeActive($query)
{
return $query->where('active', true);
}
Query Logging:
Enable Eloquent logging in config/logging.php:
'eloquent' => [
'driver' => 'single',
'level' => 'debug',
'channel' => env('LOG_CHANNEL', 'stack'),
],
ModelNotFoundException:
Catch exceptions when $fail = true in findByID():
try {
$user = $userRepo->findByID(999);
} catch (ModelNotFoundException $e) {
abort(404);
}
Pagination Issues:
Ensure $take is an integer for getAll():
// Correct:
$users = $userRepo->getAll(10);
// Avoid:
$users = $userRepo->getAll('10'); // May fail silently
Custom Methods: Add domain-specific methods to repositories:
public function getUsersWithPosts()
{
return $this->doQuery($this->newQuery()->with('posts'));
}
Model Events: Hook into Eloquent events in repositories:
public function save(array $data)
{
$model = $this->modelClass::create($data);
$model->fresh()->fireModelEvent('saved', false);
return $model;
}
Caching:
Cache repository results (e.g., getAll):
public function getAll($take = 15, $paginate = true)
{
return Cache::remember("users_{$take}_{$paginate}", now()->addHours(1), function () use ($take, $paginate) {
return parent::getAll($take, $paginate);
});
}
Testing: Mock repositories in tests:
$mockRepo = Mockery::mock(UserRepository::class);
$mockRepo->shouldReceive('getAll')->andReturn(collect([$fakeUser]));
WarehouseServiceProvider if using Fractal. Otherwise, skip it.protected $modelClass in your repository class.getAll() defaults to pagination ($paginate = true). Pass false to disable:
$users = $userRepo->getAll(10, false); // Returns Collection, not Paginator
How can I help you explore Laravel packages today?