elegantmedia/laravel-simple-repository

Lightweight Repository pattern for Laravel 10 projects. Includes a repository generator.

v3.0.0 2023-03-07 00:16 UTC

This package is auto-updated.

Last update: 2024-11-07 03:50:17 UTC


README

Latest Version on Packagist Software License

Simple repository pattern for Laravel's Eloquent models.

Why Repositories?

You can still use Eloquent queries to fetch models directly. Purpose of Repositories are to offer a standard API (or an interface), so you have a reliable layer between ORM and the controllers. This will reduce duplication and keep code clean on large applications.

Here's an example where why you may need this.

Finding an Eloquent Model by id. Here you limit column names retrived from database.

$person = Person::find(1, ['first_name', 'last_name']);

You can also do it with a repository, but to fetch relationships (which is a lot more common in large applications).

$peopleRepo = new PeopleRepository();
$person = $peopleRepo->find(1, ['profile', 'employee_records']); 

Then on the repository, you can add some common checks such as checking authorisation, filtering data based on what you retrieve etc.

Install

Install via Composer

composer require elegantmedia/laravel-simple-repository

Usage

Repository Generator

Create a new repository with make:repository command. By default, they'll be stored in Models directory.

php artisan make:repository Car

// this will create
app/Models/CarsRepository.php

The following options are also available.

// overwrite existing file
php artisan make:repository Car --force

// change the default directory to `Entities`
php artisan make:repository Car --dir Entities

By default, the the related model will be guessed. For example, if you're creating CarsRepository we can assume the associated model will be Car in the same directory. But if you want to change it, you can pass that as an argument.

// change default associated model
php artisan make:repository Car --model Vehicles\\SuperCar

To keep folders clean, you can group the Model+Repository to a single folder.

php artisan make:repository Car --group

When you do this, a new plural directory will be automatically created. For example, Cars in this example. The file structure can look like this.

// command
php artisan make:repository Car --dir Entities --group

// file structure (Car.php is an example and created by this command)
app/Entities/Cars/CarsRepository.php
app/Entities/Cars/Car.php

Search

Model

To add basic SQL LIKE search to a model, add the SearchableLike trait to a model.

namespace App\Models\User;

use Illuminate\Database\Eloquent\Model;
use ElegantMedia\SimpleRepository\Search\Eloquent\SearchableLike;

class User Extends Model 
{

	use SearchableLike;
	
	protected $searchable = [
		'name',
		'email',
	];

}

Now you can do SQL based keyword searches on Models directly.

use App\Models\User;

// get all users where `name` or `email` matches `john`
// This will return a paginator
$users = User::search('john');

Repository

You can call search on a repository to build advanced reusable filters.

First, setup the repository

<?php

namespace App\Models;

use ElegantMedia\SimpleRepository\SimpleBaseRepository as BaseRepository;

class UsersRepository extends BaseRepository
{

	// bind the model to the Repository
	public function __construct(User $model)
	{
		parent::__construct($model);
	}

}

Then call search on your repository. Usually this happens from a controller or a parent repository.

use App\Models\UsersRepository;
use App\Models\User;

$repo = app(UsersRepository::class);

$keyword = 'jane';

// Example: Get paginated results of all Users, that has a `name` or `email` LIKE `jane`
$matchedUsers = User::search($keyword)->paginate();

// Same result can be achieved with the repository. 
// If a null value is passed, it will get the `q` parameter from Request as the keyword
$matchedUsers = $repo->search();

Because the SearchFilter is a query itself, you can use it to chain conditions.

$filter = $repo->newSearchFilter();

// Example: Get results, `with` related models
$filter->with(['roles', 'projects']);

// Example: Only include Users, if `projects` have a status of `completed`
$filter->whereHas('projects', function($q) {
	$q->where('status', 'completed');
});

// Paginated results
$users = $repo->search($filter);

// Change results per page
$filter->setPerPage(100):

// Non-paginated results
$filter->paginate(false);
$users = $repo->search($filter);

The default filter will add q from query string, and sort results in descending order. If you don't want that, create a filter without the defaults.

$filter = $repo->newSearchFilter(false);

Change log

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING and for details.

Credits

License

The MIT License (MIT). Please see License File for more information.