PHPackages                             adobrovolsky97/laravel-repository-service-pattern - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. adobrovolsky97/laravel-repository-service-pattern

ActiveLibrary[Database &amp; ORM](/categories/database)

adobrovolsky97/laravel-repository-service-pattern
=================================================

Laravel 5|6|7|8|9|10 - Repository - Service Pattern

v2.18(2mo ago)275.4k↓42.9%6MITPHPPHP &gt;=7.2

Since Jun 13Pushed 2mo ago3 watchersCompare

[ Source](https://github.com/adobrovolsky97/laravel-repository-service-pattern)[ Packagist](https://packagist.org/packages/adobrovolsky97/laravel-repository-service-pattern)[ RSS](/packages/adobrovolsky97-laravel-repository-service-pattern/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (10)Dependencies (3)Versions (27)Used By (0)

Laravel 5.x+ Repository-Service Pattern
=======================================

[](#laravel-5x-repository-service-pattern)

The repository service pattern in Laravel is a widely used architectural pattern that provides a structured approach to accessing and managing data in an application. It serves as an intermediary layer between the application's business logic and the underlying data storage mechanism, such as a database.

The purpose of using the repository service pattern in Laravel is to decouple the application's business logic from the specific implementation details of data storage. By doing so, it promotes code reusability, maintainability, and testability. The pattern achieves this by defining a set of interfaces or contracts that represent the operations and queries related to data access.

Here are some key purposes and benefits of using the repository service pattern in Laravel:

- Abstraction and encapsulation: The pattern abstracts away the underlying data storage technology, allowing the application to switch between different storage mechanisms (e.g., databases, APIs) without affecting the business logic. This encapsulation ensures that the application is not tightly coupled to a specific data source, increasing its flexibility.
- Separation of concerns: The repository service pattern separates the responsibilities of data access and manipulation from the rest of the application's code. This separation enhances the maintainability of the codebase by clearly defining the boundaries and responsibilities of each component.
- Testability: By using repositories as an abstraction layer, it becomes easier to write unit tests for the application's business logic. Mock implementations can be used during testing, allowing the business logic to be tested independently of the actual data storage.
- Code organization and reusability: The pattern promotes a structured approach to organizing code related to data access. It provides a clear and consistent API for data operations, making it easier for developers to understand and work with the data layer. Additionally, repositories can be reused across different parts of the application, avoiding code duplication.
- Caching and performance optimizations: With the repository service pattern, you can implement caching strategies at the repository level. This allows you to optimize performance by caching frequently accessed data, reducing the number of queries made to the underlying data storage.

Overall, the repository service pattern in Laravel provides a structured and flexible approach to managing data access in applications, contributing to better code organization, maintainability, and testability.

Supports soft delete functionality (via trait or custom column).

Supports composite model keys.

Installation
------------

[](#installation)

### Composer

[](#composer)

Execute the following command to get the latest version of the package:

```
composer require adobrovolsky97/laravel-repository-service-pattern

```

Methods
-------

[](#methods)

### Adobrovolsky97\\LaravelRepositoryServicePattern\\Repositories\\Contracts\\BaseRepositoryInterface

[](#adobrovolsky97laravelrepositoryservicepatternrepositoriescontractsbaserepositoryinterface)

- `with(array $with): self` - define eager loading relations to append to the query
- `withCount(array $withCount): self` - define eager loading relations count to append to the query
- `withTrashed(): self` - add trashed models to the query result (if model supports Soft Delete)
- `onlyTrashed(): self` - return only trashed models as a query result (if model supports Soft Delete)
- `withoutTrashed(): self` - remove trashed models from the query result (if model supports Soft Delete)
- `find(mixed $key): ?Model` - find model by primary key
- `findOrFail(mixed $key, ?string $column = null): ?Model` - find or fail model by PK or another field
- `findFirst(array $attributes): ?Model` - find first model by given attributes, e.g `[['email', 'test@email.com'], ['anotherProperty', '>=', 'val']]`
- `findMany(array $attributes): ?Model` - find many models by given attributes, e.g `[['email', 'test@email.com'], ['anotherProperty', '>=', 'val']]`
- `getAll(array $search = []): Collection` - get collection of models (and apply filters)
- `getAllCursor(array $search = []): LazyCollection` - get collection of models as cursor (and apply filters)
- `getAllPaginated(array $search = [], int $pageSize): LengthAwarePaginator` - get collection of models with pagination (and apply filters), pageSize can be changed dynamically by passing query param `page_size`
- `count(array $search = []): int` - get count of models which fit search criteria
- `create(array $data): ?Model` - create model entity
- `insert(array $data): bool` - bulk data insert
- `update(mixed $keyOrModel, array $data): Model` - update model entity
- `updateOrCreate(array $attributes, array $data): ?Model` - update or create model if not exists
- `delete(mixed $keyOrModel): bool` - delete model (or forceDelete if model supports Soft Delete)
- `softDelete(mixed $keyOrModel): void` - soft delete model (if model supports Soft Delete)
- `restore(mixed $keyOrModel): void` - restore model (if model supports Soft Delete)

### Adobrovolsky97\\LaravelRepositoryServicePattern\\Repositories\\Contracts\\BaseCachableRepositoryInterface

[](#adobrovolsky97laravelrepositoryservicepatternrepositoriescontractsbasecachablerepositoryinterface)

This one supports the same methods, the only difference that it supports caching models &amp; collections

### Adobrovolsky97\\LaravelRepositoryServicePattern\\Services\\Contracts\\BaseCrudServiceInterface

[](#adobrovolsky97laravelrepositoryservicepatternservicescontractsbasecrudserviceinterface)

- `with(array $with): self` - define eager loading relations to append to the query
- `withCount(array $withCount): self` - define eager loading relations count to append to the query
- `withTrashed(): self` - add trashed models to the query result (if model supports Soft Delete)
- `onlyTrashed(): self` - return only trashed models as a query result (if model supports Soft Delete)
- `withoutTrashed(): self` - remove trashed models from the query result (if model supports Soft Delete)
- `getAll(array $search = []): Collection` - get collection of models (and apply filters)
- `getAllCursor(array $search = []): LazyCollection` - get collection of models as cursor (and apply filters)
- `getAllPaginated(array $search = [], int $pageSize): LengthAwarePaginator` - get collection of models with pagination (and apply filters), pageSize can be changed dynamically by passing query param `page_size`
- `count(array $search = []): int` - get count of models which fit search criteria
- `find(mixed $key): ?Model` - find model by primary key
- `findOrFail(mixed $key, ?string $column = null): ?Model` - find or fail model by PK or another field
- `create(array $data): ?Model` - create model entity
- `createMany(array $data): Collection` - create many models
- `insert(array $data): bool` - bulk data insert
- `update(mixed $keyOrModel, array $data): Model` - update model entity
- `updateOrCreate(array $attributes, array $data): ?Model` - update or create model if not exists
- `delete(mixed $keyOrModel): bool` - delete model (or forceDelete if model supports Soft Delete)
- `deleteMany(array $keysOrModels): void` - delete models (or forceDelete if model supports Soft Delete)
- `softDelete(mixed $keyOrModel): void` - soft delete model (if model supports Soft Delete)
- `restore(mixed $keyOrModel): void` - restore model (if model supports Soft Delete)

Usage
-----

[](#usage)

### Create a Model

[](#create-a-model)

Create your model e.g `Post`

```
namespace App;

class Post extends Model {

    protected $fillable = [
        'title',
        'author',
        ...
     ];

     ...
}
```

### Create Repository

[](#create-repository)

```
namespace App;

use Adobrovolsky97\LaravelRepositoryServicePattern\Repositories\BaseRepository;

class PostRepository extends BaseRepository implements PostRepositoryInterface {

    /**
     * Specify Model class name
     *
     * @return string
     */
    protected function getModelClass(): string
    {
        return Post::class;
    }
}
```

### Create Service

[](#create-service)

```
namespace App;

use Adobrovolsky97\LaravelRepositoryServicePattern\Repositories\BaseRepository;

class PostService extends BaseCrudService implements PostServiceInerface {

    /**
     * Specify Repository class name
     *
     * @return string
     */
    protected function getRepositoryClass(): string
    {
        return PostRepositoryInteface::class;
    }
}
```

### Link Service to its contract in ServiceProvider

[](#link-service-to-its-contract-in-serviceprovider)

```
class AppServiceProvider extends ServiceProvider {

    /**
     * Specify Repository class name
     *
     * @return string
     */
    public function register(): void
    {
        $this->app->singleton(PostRepositoryInterface::class, PostRepository::class);
        $this->app->singleton(PostServiceInterface::class, PostService::class);
    }
}
```

Now the Service is ready for work.

### Use methods

[](#use-methods)

```
namespace App\Http\Controllers;

use App\PostServiceInterface;

class PostsController extends Controller {

    /**
     * @var PostServiceInterface
     */
    protected PostServiceInterface $service;

    public function __construct(PostServiceInterface $service)
    {
        $this->service = $service;
    }
    ....
}
```

CRUD Controller Actions Example

Index

```
public function index(SearchRequest $request): AnonymousResourceCollection
{
    return PostResource::collection($this->service->withTrashed()->getAllPaginated($request->validated(), 25));
}
```

Show

```
public function show(int $postId): PostResource
{
    return PostResource::make($this->service->findOrFail($postId));
}
```

Store

```
public function store(StoreRequest $request): PostResource
{
    return PostResource::make($this->service->create($request->validated()));
}
```

Update

```
public function update(Post $post, UpdateRequest $request): PostResource
{
    return PostResource::make($this->service->update($post, $request->validated()));
}
```

Destroy

```
public function destroy(Post $post): JsonResponse
{
    $this->service->delete($post);
    // Or
    $this->service->softDelete($post);

    return Response::json(null, 204);
}
```

Restore

```
public function restore(Post $deletedPost): PostResource
{
    $this->service->restore($deletedPost);

    return PostResource::make($deletedPost->refresh());
}
```

### Soft Deletes

[](#soft-deletes)

You need to add at least soft delete column (`deleted_at`) to the table to start using soft deletes from the service.

Also, it is possible to use it together with `SoftDeletes` trait

By default soft delete column name is `deleted_at`, you may override it by defining variable inside your repository

`protected $deletedAtColumnName = 'custom_deleted_at';`

By default, soft deleted records excluded from the query result data

```
$posts = $this->service->getAll();
// Those are equivalent
$posts = $this->service->withoutTrashed()->getAll();
```

Showing only soft deleted records

```
$posts = $this->service->onlyTrashed()->getAll();
```

Showing only NOT soft deleted records

```
$posts = $this->service->withoutTrashed()->getAll();
```

### Loading the Model relationships

[](#loading-the-model-relationships)

```
$post = $this->service->with(['author'])->withCount(['readers'])->getAll();
```

### Query results filtering

[](#query-results-filtering)

By default filtering will be handled by `applyFilterConditions()`, but you may probably need to do custom filtering, so override `applyFilters` method in your repository if you need custom filtering

```
class PostRepository extends BaseRepository implements PostRepositoryInterface {

   /**
    * Override this method in your repository if you need custom filtering
    *
    * @param array $searchParams
    * @return Builder
    */
    protected function applyFilters(array $searchParams = []): Builder
    {
        return $this
            ->getQuery()
            ->when(isset($searchParams['title']), function (Builder $query) use ($searchParams) {
                $query->where('title', 'like', "%{$searchParams['title']}%");
            })
            ->orderBy('id');
    }
}
```

Find many models by multiple fields

```
$posts = $this->repository->findMany([
    'field' => 'val' // where('field', '=', 'val')
    ['field', 'val'], // where('field', '=', 'val')
    ['field' => 'val'], // where('field', '=', 'val')
    ['field', '=', 'val'], // where('field', '=', 'val')
    ['field', '>', 'val'], // where('field', '>', 'val')
    ['field', 'like', '%val%'], // where('field', 'like', '%val%')
    ['field', 'in', [1,2,3]], // whereIn('field', [1,2,3])
    ['field', 'not_in', [1,2,3]], // whereNotIn('field', [1,2,3])
    ['field', 'null'], // whereNull($field)
    ['field', 'not_null'], // whereNotNull($field)
    ['field', 'date', '2022-01-01'], // whereDate($field, '=', '2022-01-01')
    ['field', 'date =', '2022-01-01'], // whereDate($field, '>=', '2022-01-01')
    ['field', 'day >=', '01'], // whereDay($field, '>=', '01')
    ['field', 'day', '01'], // whereDay($field, '=', '01')
    ['field', 'month', '01'], // whereMonth($field, '=', '01')
    ['field', 'month
