PHPackages                             elegantmedia/laravel-simple-repository - 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. elegantmedia/laravel-simple-repository

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

elegantmedia/laravel-simple-repository
======================================

Lightweight Repository pattern for Laravel 12+ projects with strict typing and modern PHP features.

v5.0.1(6mo ago)011.4k↓36.4%11MITPHPPHP ^8.2CI passing

Since Oct 28Pushed 5mo ago3 watchersCompare

[ Source](https://github.com/elegantmedia/laravel-simple-repository)[ Packagist](https://packagist.org/packages/elegantmedia/laravel-simple-repository)[ Docs](https://github.com/elegantmedia/Laravel-Simple-Repository)[ RSS](/packages/elegantmedia-laravel-simple-repository/feed)WikiDiscussions v5.x Synced 1mo ago

READMEChangelog (9)Dependencies (9)Versions (12)Used By (1)

Laravel Simple Repository
=========================

[](#laravel-simple-repository)

[![Latest Version on Packagist](https://camo.githubusercontent.com/f32b88994ed7987844903d813620c46ed73b065d11e88f83ab96860511481670/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f656c6567616e746d656469612f6c61726176656c2d73696d706c652d7265706f7369746f72792e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/elegantmedia/laravel-simple-repository)[![Software License](https://camo.githubusercontent.com/55c0218c8f8009f06ad4ddae837ddd05301481fcf0dff8e0ed9dadda8780713e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265)](LICENSE.md)[![CI Status](https://github.com/elegantmedia/Laravel-Simple-Repository/actions/workflows/ci.yml/badge.svg)](https://github.com/elegantmedia/Laravel-Simple-Repository/actions/workflows/ci.yml)[![Code Coverage](https://camo.githubusercontent.com/21b7008f051b0407a52aa1e6a749a4cb2c143b70a1d6de5de1acf83fa1058994/68747470733a2f2f636f6465636f762e696f2f67682f656c6567616e746d656469612f4c61726176656c2d53696d706c652d5265706f7369746f72792f6272616e63682f76352e782f67726170682f62616467652e737667)](https://codecov.io/gh/elegantmedia/Laravel-Simple-Repository)

A clean and type-safe implementation of the repository pattern for Laravel 12+ applications.

Version Compatibility
---------------------

[](#version-compatibility)

Package VersionLaravel VersionPHP VersionBranch5.x12.x^8.2v5.x4.x11.x^8.2v4.x3.x10.x^8.1master2.x9.x^8.0masterDocumentation
-------------

[](#documentation)

- **[Architecture Guide](docs/ARCHITECTURE.md)** - Understand the design decisions, patterns, and component relationships
- **[Development Guide](docs/DEVELOPMENT.md)** - Contributing guidelines, testing strategies, and development workflow
- **[Migration Guide](docs/MIGRATION_GUIDE_v4-v5.md)** - Upgrade from v4.x to v5.x with breaking changes and new features
- **[Examples](examples/EXAMPLES.md)** - Complete working examples showing real-world usage patterns
- **[Changelog](CHANGELOG.md)** - Version history and release notes

What is Laravel Simple Repository?
----------------------------------

[](#what-is-laravel-simple-repository)

Laravel Simple Repository provides a powerful abstraction layer between your application logic and data persistence. It implements the repository pattern with modern PHP features, offering a clean, maintainable, and testable approach to data access.

### Why Use This Package?

[](#why-use-this-package)

- **Separation of Concerns**: Keep your controllers thin and your models focused on business logic by moving data access to dedicated repository classes
- **Type Safety**: Built with PHP 8.2+ features for full type hinting and IDE autocompletion support
- **Testability**: Easy to mock and test your data layer without touching the database
- **Consistency**: Standardized API across all your repositories with common operations pre-built
- **Flexibility**: Advanced filtering system that doesn't duplicate Laravel's query builder
- **Performance**: Built-in support for eager loading, pagination, and query optimization
- **Transaction Safety**: Comprehensive transaction support for data integrity

Repository Methods
------------------

[](#repository-methods)

### Complete Method Reference

[](#complete-method-reference)

MethodDescription**Query Building**`newModel()`Create a new instance of the model`newQuery()`Create a new query builder instance`newFilter($defaults = true)`Create a new filter instance for complex queries**List/Search Operations**`all($with = [])`Get all models with optional relationships`paginate($perPage = 50, $with = [], $filter = null)`Paginate results with optional relationships and filters`simplePaginate($perPage = 50, $with = [], $filter = null)`Simple pagination without total count`search($filter = null)`Search models using the provided filter`searchByTerm($term)`Simple search for models by a search term`searchPaginated($term, $perPage = 50)`Search models with pagination**Find Operations**`find($id, $with = [])`Find a model by its primary key`findByUuid($uuid, $with = [])`Find a model by UUID`findByField($field, $value, $with = [])`Find a model by a specific field value`findOrCreate($searchAttributes, $additionalAttributes = [])`Find or create a model with given attributes`findOrCreateById($id, $attributes, $idColumn = 'id')`Find or create a model by ID`findOrFail($id)`Find a model by ID or throw exception`findByFieldOrFail($field, $value)`Find by field or throw exception`findWithTrashed($id)`Find including soft deleted records`findOnlyTrashed($id)`Find from soft deleted records only`findMany($ids)`Find multiple models by their primary keys`findManyByField($field, $value)`Find multiple models by field value**Create Operations**`create($attributes)`Create a new model instance`createMany($records)`Create multiple model instances`firstOrNew($attributes, $values = [])`Get first matching model or instantiate new`firstOrCreate($attributes, $values = [])`Get first matching model or create it**Update Operations**`updateModel($model, $attributes)`Update a model instance`updateById($id, $attributes, $idColumn = 'id')`Update a model by ID`updateWhere($where, $data)`Update models matching conditions`updateOrCreateById($id, $attributes, $idColumn = 'id')`Update or create a model by ID`updateOrCreateByUuid($attributes)`Update or create a model by UUID`save($model)`Save a model instance**Delete Operations**`delete($id)`Delete a model by ID`deleteWhere($where)`Delete models matching conditions`deleteManyByIds($ids)`Delete multiple models by IDs`restore($id)`Restore a soft deleted model`forceDelete($id)`Permanently delete a model**Aggregate Methods**`sum($column, $where = [])`Get the sum of a column`avg($column, $where = [])`Get the average of a column`min($column, $where = [])`Get the minimum value of a column`max($column, $where = [])`Get the maximum value of a column`count($where = [])`Count models matching conditions**Utility Methods**`exists($where = [])`Check if models exist with conditions`value($column, $where = [])`Get single column value from first result`pluck($column, $where = [], $key = null)`Get array of column values`chunk($count, $callback, $where = [])`Process results in chunks`random($count = 1)`Get random model(s)**Transaction Methods**`withTransaction($enabled = true)`Enable/disable automatic transaction wrapping`transaction($callback)`Execute callback within a transaction`beginTransaction()`Start a new database transaction`commit()`Commit the active transaction`rollback()`Rollback the active transaction`transactionLevel()`Get number of active transactions**Model Information**`getModelClass()`Get the fully qualified class name`getModel()`Get the model instanceFilter Methods
--------------

[](#filter-methods)

The SearchFilter class provides powerful query building capabilities through composition. These methods can be chained to build complex queries.

### Laravel Query Builder Methods

[](#laravel-query-builder-methods)

**Important**: The SearchFilter class automatically inherits ALL Laravel query builder methods through composition. This means you can use any Eloquent query builder method like `where()`, `whereIn()`, `whereNull()`, `whereBetween()`, `whereHas()`, `orderBy()`, `with()`, `select()`, `join()`, `groupBy()`, and many more without us having to duplicate them in our codebase.

```
// All Laravel query builder methods are available
$filter = $repository->newFilter()
    ->where('status', 'active')
    ->whereIn('role', ['admin', 'moderator'])
    ->whereHas('posts', function ($query) {
        $query->where('published', true);
    })
    ->with(['profile', 'posts'])
    ->orderBy('created_at', 'desc')
    ->select('id', 'name', 'email');
```

### Repository-Specific Filter Methods

[](#repository-specific-filter-methods)

These are custom methods provided by the repository pattern that enhance the filtering experience:

MethodDescription`setKeyword($keyword)`Set search keyword for searchable models`setSortBy($field)`Set the default sort field`setSortDirection($direction)`Set sort direction ('asc' or 'desc')`setPaginate($paginate = true)`Enable/disable pagination`setPerPage($perPage)`Set items per page (max 100)### Date Filtering Methods

[](#date-filtering-methods)

These methods are available through the `DateFilterableTrait` and provide convenient date-based filtering:

MethodDescription`whereDateIs($date, $column = 'created_at')`Filter where date equals the given date`whereDateTimeIs($dateTime, $column = 'created_at')`Filter where datetime equals the given datetime`whereDateBefore($date, $column = 'created_at')`Filter where date is before the given date`whereDateAfter($date, $column = 'created_at')`Filter where date is after the given date`whereDateBetween($start, $end, $column = 'created_at')`Filter where date is between two dates (inclusive)`whereDateInPeriod($period, $column = 'created_at')`Filter where date is within a Carbon period`whereDateWithin($interval, $column = 'created_at')`Filter within interval from now (e.g., last 7 days)`whereDateToday($column = 'created_at')`Filter records created today`whereDateYesterday($column = 'created_at')`Filter records created yesterday`whereDateThisWeek($column = 'created_at')`Filter records created this week`whereDateLastWeek($column = 'created_at')`Filter records created last week`whereDateThisMonth($column = 'created_at')`Filter records created this month`whereDateLastMonth($column = 'created_at')`Filter records created last month`whereDateThisYear($column = 'created_at')`Filter records created this year`whereDateLastYear($column = 'created_at')`Filter records created last year`whereDateLastDays($days, $column = 'created_at')`Filter records created in the last N days`whereDateLastHours($hours, $column = 'created_at')`Filter records created in the last N hours`whereDateLastMinutes($minutes, $column = 'created_at')`Filter records created in the last N minutes### Financial Date Filtering Methods

[](#financial-date-filtering-methods)

These methods are available through the `FinancialDateFilterableTrait` and provide financial period filtering:

MethodDescription`whereDateThisQuarter($column = 'created_at')`Filter records created this quarter`whereDateLastQuarter($column = 'created_at')`Filter records created last quarter`whereDateInQuarter($quarter, $year = null, $column = 'created_at')`Filter records in a specific quarter (1-4)`whereDateInThisFinancialYear($column = 'created_at')`Filter records in current financial year (Jul-Jun)`whereDateInLastFinancialYear($column = 'created_at')`Filter records in last financial year`whereDateInFinancialYear($endingYear, $column = 'created_at')`Filter records in specific financial year### Usage Examples

[](#usage-examples)

```
// Create a filter with date conditions
$filter = $repository->newFilter()
    ->whereDateThisMonth()
    ->whereDateInThisFinancialYear('revenue_date')
    ->where('status', 'active')
    ->orderBy('created_at', 'desc');

// Apply the filter
$results = $repository->search($filter);
```

Detailed Usage Examples
-----------------------

[](#detailed-usage-examples)

### Query Building Methods

[](#query-building-methods)

```
// newModel() - Create a new model instance without saving
$user = $repository->newModel();
$user->name = 'John Doe';
$user->email = 'john@example.com';
$repository->save($user);

// newQuery() - Get a query builder for complex operations
$query = $repository->newQuery()
    ->where('active', true)
    ->whereYear('created_at', 2024);
$count = $query->count();

// newFilter() - Create a reusable filter
$activeUsersFilter = $repository->newFilter()
    ->where('status', 'active')
    ->where('verified', true);
```

### When to Use newFilter() vs newQuery()

[](#when-to-use-newfilter-vs-newquery)

#### Use `newFilter()` for:

[](#use-newfilter-for)

- **Search and filtering operations** - When you need to build complex search queries
- **Reusable query configurations** - When you want to define a filter once and use it multiple times
- **Dynamic queries** - When building queries based on user input or request parameters
- **Paginated results** - When you need built-in pagination control
- **Repository pattern adherence** - When you want to maintain clean separation of concerns

```
// Example: Building a reusable filter for search operations
$filter = $repository->newFilter()
    ->setKeyword('Laravel')
    ->where('status', 'active')
    ->whereIn('category', ['tutorial', 'guide'])
    ->whereDateThisMonth()
    ->setSortBy('views')
    ->setSortDirection('desc')
    ->setPaginate(true)
    ->setPerPage(20);

// Use the filter with repository methods
$results = $repository->search($filter);  // Returns paginated results
$allResults = $repository->paginate(50, [], $filter);  // Custom pagination
```

#### Use `newQuery()` for:

[](#use-newquery-for)

- **Direct query operations** - When you need raw access to Laravel's query builder
- **Custom aggregations** - When the repository's aggregate methods aren't sufficient
- **Complex joins or subqueries** - When you need advanced SQL operations
- **One-off queries** - When you don't need the filter's features
- **Performance-critical operations** - When you need maximum control over the query

```
// Example: Direct query builder for custom operations
$query = $repository->newQuery()
    ->select('department', DB::raw('COUNT(*) as total'))
    ->where('active', true)
    ->groupBy('department')
    ->having('total', '>', 10);

$departments = $query->get();

// Example: Complex join operation
$results = $repository->newQuery()
    ->join('posts', 'users.id', '=', 'posts.user_id')
    ->where('posts.published', true)
    ->whereYear('posts.created_at', 2024)
    ->select('users.*', DB::raw('COUNT(posts.id) as post_count'))
    ->groupBy('users.id')
    ->orderBy('post_count', 'desc')
    ->limit(10)
    ->get();
```

#### Key Differences:

[](#key-differences)

FeaturenewFilter()newQuery()**Purpose**Search and filtering with repository patternDirect Eloquent query builder access**Return Type**FilterableInterfaceEloquent\\Builder**Pagination**Built-in pagination controlManual pagination required**Reusability**Designed for reuseOne-time use**Search Features**`setKeyword()` for model's searchable fieldsManual search implementation**Method Chaining**Repository-specific + Laravel methodsOnly Laravel query builder methods**Best For**Application search features, API filtersComplex SQL, performance-critical queries### Pagination Methods

[](#pagination-methods)

```
// paginate() - Standard Laravel pagination with total count
$users = $repository->paginate(20); // 20 items per page
$users = $repository->paginate(20, ['profile', 'posts']); // With eager loading
$users = $repository->paginate(20, [], $filter); // With custom filter

// simplePaginate() - More efficient pagination without total count
$users = $repository->simplePaginate(50); // Faster for large datasets
$users = $repository->simplePaginate(50, ['profile']); // With relations
```

### Search Methods

[](#search-methods)

```
// search() - Flexible search that respects filter's pagination setting
$filter = $repository->newFilter()
    ->setKeyword('john')
    ->setPaginate(true)
    ->setPerPage(20);
$results = $repository->search($filter); // Returns LengthAwarePaginator

$filter->setPaginate(false);
$results = $repository->search($filter); // Returns Collection

// searchByTerm() - Simple search returning all results
$users = $repository->searchByTerm('john@example.com'); // Returns Collection
// Good for autocomplete, dropdowns, or small result sets

// searchPaginated() - Always returns paginated results
$results = $repository->searchPaginated('john', 25); // 25 per page
$results = $repository->searchPaginated('admin', 10); // 10 per page
// Perfect for search results pages, data tables
```

### Update Methods

[](#update-methods)

```
// updateModel() - Update an existing model instance
$user = $repository->find(1);
$updated = $repository->updateModel($user, [
    'name' => 'Jane Doe',
    'email' => 'jane@example.com'
]);

// updateById() - Update without fetching the model first
$updated = $repository->updateById(1, [
    'last_login' => now(),
    'login_count' => DB::raw('login_count + 1')
]);

// updateWhere() - Bulk update with conditions
$affectedRows = $repository->updateWhere(
    ['status' => 'pending', 'created_at' => '=', now()->startOfMonth()
]);

// avg() - Calculate average
$averagePrice = $repository->avg('price');
$averageRating = $repository->avg('rating', ['status' => 'published']);

// min() - Get minimum value
$lowestPrice = $repository->min('price');
$earliestDate = $repository->min('created_at', ['status' => 'active']);
```

### Utility Methods

[](#utility-methods)

```
// exists() - Check if records exist
if ($repository->exists(['email' => 'john@example.com'])) {
    // Email already taken
}

// value() - Get a single column value
$userName = $repository->value('name', ['id' => 1]);
$latestLogin = $repository->value('last_login', ['email' => 'john@example.com']);

// pluck() - Get array of values
$names = $repository->pluck('name'); // Collection of all names
$emailsByName = $repository->pluck('email', [], 'name'); // Keyed by name
$activeEmails = $repository->pluck('email', ['status' => 'active']);

// chunk() - Process large datasets efficiently
$repository->chunk(1000, function ($users) {
    foreach ($users as $user) {
        // Process each user
        Mail::to($user)->send(new Newsletter());
    }
}, ['subscribed' => true]);

// random() - Get random records
$randomUser = $repository->random(); // Single random model
$randomUsers = $repository->random(5); // Collection of 5 random models
```

### Transaction Methods

[](#transaction-methods)

```
// withTransaction() - Enable automatic transactions
$repository->withTransaction(); // Enable
$user = $repository->create(['name' => 'John']); // Wrapped in transaction
$repository->updateModel($user, ['verified' => true]); // Also wrapped
$repository->withTransaction(false); // Disable

// transaction() - Callback-based transactions
$result = $repository->transaction(function ($repo) {
    $user = $repo->create(['name' => 'Jane']);
    $profile = $repo->create(['user_id' => $user->id]);

    if (!$user->isValid()) {
        throw new \Exception('Invalid user');
    }

    return $user;
}); // Automatically rolled back on exception
```

### Filter-Specific Methods

[](#filter-specific-methods)

```
// setKeyword() - Search in model's searchable fields
$filter = $repository->newFilter()
    ->setKeyword('john doe'); // Searches in fields defined by model

// setSortBy() and setSortDirection()
$filter->setSortBy('created_at')
    ->setSortDirection('desc'); // Latest first

// setPaginate() - Control pagination behavior
$filter->setPaginate(true); // Enable pagination
$filter->setPaginate(false); // Disable - returns all results

// setPerPage() - Control page size
$filter->setPerPage(100); // Max 100 items per page
$filter->setPerPage(10); // 10 items per page
```

### Date Filtering Examples

[](#date-filtering-examples)

```
use Carbon\Carbon;
use Carbon\CarbonPeriod;

// whereDateIs() - Exact date match
$filter = $repository->newFilter()
    ->whereDateIs(Carbon::parse('2024-01-15')); // All records from Jan 15, 2024

// whereDateInPeriod() - Using Carbon periods
$period = CarbonPeriod::create('2024-01-01', '2024-01-31');
$filter = $repository->newFilter()
    ->whereDateInPeriod($period); // All January 2024 records

// Custom column filtering
$filter = $repository->newFilter()
    ->whereDateIs(Carbon::today(), 'published_at')
    ->whereDateInPeriod($period, 'approved_at');
```

Quick Start
-----------

[](#quick-start)

### Installation

[](#installation)

```
composer require elegantmedia/laravel-simple-repository
```

### Configuration

[](#configuration)

Publish the configuration file to customize default settings:

```
php artisan vendor:publish --provider="ElegantMedia\SimpleRepository\SimpleRepositoryServiceProvider" --tag="simple-repository-config"
```

This will create `config/simple-repository.php` where you can configure:

- **Default Pagination**: Set default `per_page` and `max_per_page` values
- **Default Sorting**: Configure default sort field and direction
- **Search Settings**: Customize search query parameter and case sensitivity
- **Repository Command**: Set default directory and repository suffix for generated files

Example configuration:

```
return [
    'defaults' => [
        'pagination' => [
            'per_page' => 50,
            'max_per_page' => 100,
        ],
        'sorting' => [
            'field' => 'created_at',
            'direction' => 'desc',
        ],
    ],
    'search' => [
        'query_parameter' => 'q',
        'case_sensitive' => false,
    ],
    'command' => [
        'directory' => 'Models',
        'suffix' => 'Repository',
    ],
];
```

### Basic Usage

[](#basic-usage)

#### 1. Create a repository:

[](#1-create-a-repository)

```
php artisan make:repository User
```

#### 2. Use in your controller:

[](#2-use-in-your-controller)

```
