This repository demonstrates how to structure a Laravel application using Repository Pattern, Service Layer, Form Requests, API Resources, and Dependency Injection.
الهدف: فصل المسؤوليات (Separation of Concerns) وبناء تطبيق واضح وقابل للصيانة والاختبار.
- Introduction
- Why Use Repository & Service Pattern
- Installation
- Create Model
- Repository Interface
- Repository Implementation
- Service Layer
- Controller + Validation + Resource
- Routes
- Architecture Diagram
- Folder Structure
- Future Improvements
تطبيق Laravel منظم بطبقات واضحة (Repository, Service, Form Request, API Resource) وقابل للتوسع والاختبار.
A clean, layered Laravel example ready for learning and reuse.
- Controller: Handles HTTP requests and responses. — يستقبل الطلب ويرد بالنتيجة.
- Service: Contains the business logic. — يحتوي منطق العمل (Business Logic).
- Repository: Handles database interactions. — يتعامل مع قاعدة البيانات.
- Interface: Defines contracts for flexible implementations. — يعرّف التعاقد ويُسهّل التبديل والاختبار.
لتجربة المشروع محلياً / To run the project locally:
git clone git@github.com:Muhammed2024Salama/laravel-repository-service-pattern.git
cd laravel-repository-service-pattern
composer install
cp .env.example .env
php artisan key:generate
php artisan migrate
php artisan serveUse actual GitHub repository URL:
git@github.com:Muhammed2024Salama/laravel-repository-service-pattern.git
php artisan make:model Product -m-m ينشئ ملف Migration مع الموديل. / Creates a migration file.
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->decimal('price', 10, 2); // السعر بفاصلة عشرية
$table->timestamps();
});ثم: php artisan migrate
<?php
namespace App\Repositories;
use App\Models\Product;
use Illuminate\Database\Eloquent\Collection;
interface ProductRepositoryInterface
{
public function getAll(): Collection;
public function getById(int $id): Product;
public function create(array $data): Product;
public function update(int $id, array $data): Product;
public function delete(int $id): int;
}<?php
namespace App\Repositories;
use App\Models\Product;
use Illuminate\Database\Eloquent\Collection;
class ProductRepository implements ProductRepositoryInterface
{
public function getAll(): Collection
{
return Product::all();
}
public function getById(int $id): Product
{
return Product::findOrFail($id);
}
public function create(array $data): Product
{
return Product::create($data);
}
public function update(int $id, array $data): Product
{
$product = Product::findOrFail($id);
$product->update($data);
return $product;
}
public function delete(int $id): int
{
return Product::destroy($id);
}
}في app/Providers/AppServiceProvider.php داخل register():
use App\Repositories\ProductRepositoryInterface;
use App\Repositories\ProductRepository;
$this->app->bind(
ProductRepositoryInterface::class,
ProductRepository::class
);الـ Service هنا مش مجرد pass-through؛ فيه منطق فعلي (مثلاً تقريب السعر).
<?php
namespace App\Services;
use App\Repositories\ProductRepositoryInterface;
use App\Models\Product;
use Illuminate\Database\Eloquent\Collection;
class ProductService
{
public function __construct(
protected ProductRepositoryInterface $productRepository
) {}
public function getAll(): Collection
{
return $this->productRepository->getAll();
}
public function getById(int $id): Product
{
return $this->productRepository->getById($id);
}
public function create(array $data): Product
{
// Business logic مثال
if (isset($data['price'])) {
$data['price'] = round($data['price'], 2);
}
return $this->productRepository->create($data);
}
public function update(int $id, array $data): Product
{
return $this->productRepository->update($id, $data);
}
public function delete(int $id): int
{
return $this->productRepository->delete($id);
}
}- Form Request بدل
Request+$request->all()— تحقق من البيانات (Validation). - API Resource بدل
response()->json()— تنظيم شكل الـ API.
<?php
namespace App\Http\Controllers;
use App\Services\ProductService;
use App\Http\Requests\StoreProductRequest;
use App\Http\Resources\ProductResource;
class ProductController extends Controller
{
public function __construct(
protected ProductService $productService
) {}
public function index()
{
return ProductResource::collection(
$this->productService->getAll()
);
}
public function store(StoreProductRequest $request)
{
$product = $this->productService->create($request->validated());
return (new ProductResource($product))
->response()
->setStatusCode(201);
}
public function show(int $id)
{
return new ProductResource(
$this->productService->getById($id)
);
}
public function update(StoreProductRequest $request, int $id)
{
$product = $this->productService->update($id, $request->validated());
return new ProductResource($product);
}
public function destroy(int $id)
{
$this->productService->delete($id);
return response()->noContent(); // 204 No Content
}
}php artisan make:request StoreProductRequestpublic function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'price' => ['required', 'numeric', 'min:0'],
];
}php artisan make:resource ProductResourcepublic function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'price' => $this->price,
'created_at' => $this->created_at,
];
}في routes/api.php:
use App\Http\Controllers\ProductController;
Route::resource('products', ProductController::class);Client
↓
Route
↓
Controller
↓
Service Layer
↓
Repository Layer
↓
Database
app
├── Http
│ ├── Controllers
│ ├── Requests
│ └── Resources
│
├── Repositories
│ ├── ProductRepositoryInterface.php
│ └── ProductRepository.php
│
├── Services
│ └── ProductService.php
- Add Unit Tests — إضافة اختبارات وحدة للـ Service و Repository.
- Add Feature Tests — اختبارات سيناريوهات الـ API.
- Implement DTO Layer — طبقة DTO لفصل بيانات الطلب عن النطاق.
- Add Caching in Repository — تخزين مؤقت في طبقة الـ Repository.
Muhammed Salama
devmuhammedsalama@gmail.com