In this blog, we are going to learn about the Repository Pattern used in Bagisto.
We will see what it is, why Bagisto uses it, and how to implement it inside a package, with code examples.
Repository Layer Architecture in Bagisto
The Repository layer architecture in Bagisto separates data access logic from business logic.
Instead of a controller querying the database directly, it asks a repository for the data.
So, the repository handles the actual query, not the controller.
In Bagisto, every package follows this same pattern.
For example, controllers don’t call Product::where(...) or Customer::find(...) directly.
Instead, they call a method on ProductRepository or CustomerRepository.
Repository Pattern: Enhancing Maintainability and Scalability in Bagisto
Bagisto uses the Prettus L5 Repository package to provide a structured approach to data access.
This functionality is exposed through the Webkul\Core\Eloquent\Repository class, which serves as the base repository for all packages.
Also, Bagisto splits its codebase into multiple independent packages, such as Product, Customer, Sales, Category, and Checkout.
Each of these packages follows the same folder structure.
With this many packages, raw queries scattered across controllers quickly become hard to manage.
So, the Repository Pattern solves this by giving every package the same way to read and write data.
In short, it gives a few direct benefits:
- Consistency: every package accesses data the same way.
- Maintainability: query logic for an entity stays in one file.
- Flexibility: you can change how data is fetched without changing the code that calls it.
- Testability: you can mock repositories easily in tests.
Repository Architecture in Bagisto
Bagisto uses konekt/concord for model registration.
Because of this, a Bagisto model consists of three files, not just one:
- Contract – an interface, for example
Webkul\Product\Contracts\Product - Model – the Eloquent model that implements the contract
- Proxy – a class that resolves the correct model at runtime
You can read more about this in the Models documentation.
A repository sits above these three files, and it points to the contract, not the model directly:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<?php namespace Webkul\RMA\Repositories; use Webkul\Core\Eloquent\Repository; class ReturnRequestRepository extends Repository { /** * Specify the Model contract class name. */ public function model(): string { return 'Webkul\RMA\Contracts\ReturnRequest'; } } |
Here, the model() method returns the contract, not the model class.
As a result, other developers can register a different model for the same contract, without changing the repository at all.
Every repository in Bagisto extends Webkul\Core\Eloquent\Repository.
This class, in turn, wraps Prettus L5 Repository.
That’s where methods like findWhere(), paginate(), and with() come from.
Creating Custom Repositories in Bagisto
There are two ways to create a repository in Bagisto.
Method 1: Using the Package Generator
First, run this artisan command:
|
1 |
php artisan package:make-repository ReturnRequestRepository Webkul/RMA |
This command creates the file ReturnRequestRepository.php inside packages/Webkul/RMA/src/Repositories/.
Plus, the generator already sets up the namespace and base class for you.
Method 2: Creating it Manually
Alternatively, create the Repositories folder inside your package:
|
1 |
mkdir -p packages/Webkul/RMA/src/Repositories |
Then create the repository class:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<?php namespace Webkul\RMA\Repositories; use Webkul\Core\Eloquent\Repository; class ReturnRequestRepository extends Repository { /** * Specify the Model contract class name. * * @return string */ public function model(): string { return 'Webkul\RMA\Contracts\ReturnRequest'; } } |
Either way, both methods produce the same result.
For more details, check the Repositories documentation.
Repository-Driven Data Access in Bagisto
Once a repository exists, inject it into a controller.
Then, use it for every data operation instead of the model.
Create a Record
|
1 2 3 4 5 6 7 |
$returnRequest = $this->returnRequestRepository->create([ 'customer_id' => 1, 'order_id' => 123, 'product_sku' => 'SAMPLE-001', 'product_name' => 'Test Product', 'product_quantity' => 1, ]); |
Read Records
|
1 2 3 4 5 6 7 8 |
// Get all records $allReturns = $this->returnRequestRepository->all(); // Find by ID $returnRequest = $this->returnRequestRepository->find($id); // Find or throw an exception $returnRequest = $this->returnRequestRepository->findOrFail($id); |
Update a Record
|
1 2 3 4 |
$returnRequest = $this->returnRequestRepository->update([ 'status' => 'approved', 'admin_notes' => 'Approved for return', ], $id); |
Delete a Record
|
1 |
$this->returnRequestRepository->delete($id); |
Notice that none of these examples use a raw query or a direct model call.
Instead, every operation goes through the repository.
Advanced Queries
Since Bagisto repositories extend the Prettus base class, you get query helpers for free.
So, you don’t need to write manual where() chains for common cases.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// Find records matching multiple conditions $pendingReturns = $this->returnRequestRepository->findWhere([ 'status' => 'pending', 'customer_id' => 456, ]); // Find records where a column matches values in an array $specificReturns = $this->returnRequestRepository->findWhereIn('id', [1, 2, 3, 4, 5]); // Find records within a date range $recentReturns = $this->returnRequestRepository->findWhereBetween('created_at', [ '2024-01-01', '2024-12-31', ]); // Paginate results $paginatedReturns = $this->returnRequestRepository->paginate(15); // Eager load relationships $returnWithRelations = $this->returnRequestRepository ->with(['customer', 'order']) ->find($id); |
Implementing Custom Repository Methods
Beyond the basics, you can add your own methods to a repository.
This way, you can handle specific business logic in one place:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
<?php namespace Webkul\RMA\Repositories; use Webkul\Core\Eloquent\Repository; class ReturnRequestRepository extends Repository { public function model(): string { return 'Webkul\RMA\Contracts\ReturnRequest'; } /** * Get pending return requests for a specific customer. */ public function getPendingForCustomer(int $customerId) { return $this->findWhere([ 'customer_id' => $customerId, 'status' => 'pending', ]); } /** * Get return requests statistics. */ public function getStats(): array { return [ 'total' => $this->count(), 'pending' => $this->findWhere(['status' => 'pending'])->count(), 'approved' => $this->findWhere(['status' => 'approved'])->count(), 'rejected' => $this->findWhere(['status' => 'rejected'])->count(), ]; } } |
After this, a controller can simply call getPendingForCustomer($id).
Conclusion
The Repository Pattern is a core part of Bagisto’s architecture, providing a clean and consistent approach to data access.
By separating database operations from business logic, repositories improve maintainability, scalability, and code organization.
When developing custom packages, following this pattern ensures your code remains aligned with Bagisto’s standards and is easier to extend in the future.
Thanks for reading this blog. I hope it helped you understand how the Repository Pattern works in Bagisto.
If you found this post helpful, please share your feedback in the comments. Your insights help us create better content for the community.
You can visit the hire laravel developers This platform provides a pool of experienced Laravel developers.
For exploring the available extensions for Bagisto, you can check out extensions.