Contributing Guide
Code standards, best practices, and contribution guidelines for ZÈYA API.
Code Standards
1. Follow Laravel Conventions
- Use Laravel naming conventions
- Follow PSR-12 coding standards
- Use Laravel's built-in features
- Follow RESTful conventions
2. Use Form Requests for Validation
✅ Good:
public function store(StoreProductRequest $request)
{
$validated = $request->validated();
// ...
}
❌ Bad:
public function store(Request $request)
{
$request->validate([
'title' => 'required',
]);
// ...
}
3. Keep Controllers Thin
Delegate business logic to Services:
✅ Good:
public function store(StoreProductRequest $request, ProductService $service)
{
$product = $service->createProduct($request->validated(), $request->user());
return new ProductResource($product);
}
❌ Bad:
public function store(StoreProductRequest $request)
{
// 50+ lines of business logic here
}
4. Use API Resources
Transform responses consistently:
✅ Good:
return new ProductResource($product);
return ProductResource::collection($products);
❌ Bad:
return response()->json([
'id' => $product->id,
'title' => $product->title,
// Inconsistent structure
]);
5. Prevent N+1 Queries
Always eager load relationships:
✅ Good:
$products = Product::with(['owner', 'category', 'images'])->get();
❌ Bad:
$products = Product::all();
foreach ($products as $product) {
$product->owner; // N+1 query!
}
6. Use Transactions
For multiple database operations:
✅ Good:
DB::transaction(function () use ($data) {
$product = Product::create($data);
$product->images()->createMany($imageData);
});
❌ Bad:
$product = Product::create($data);
$product->images()->createMany($imageData);
// If second fails, product is created but no images!
Development Workflow
1. Create Feature Branch
git checkout -b feature/your-feature-name
2. Make Changes
- Follow coding standards
- Write clean, readable code
- Add comments where necessary
- Keep functions small and focused
3. Write Tests
# Create test file
php artisan make:test ProductTest
# Write tests
# Run tests
php artisan test --filter ProductTest
4. Format Code
php artisan pint
5. Commit Changes
Use conventional commit messages:
feat: add product search feature
fix: resolve authentication bug
docs: update API documentation
refactor: improve product service
test: add product tests
chore: update dependencies
6. Push and Create PR
git push origin feature/your-feature-name
Code Review Checklist
Before submitting a PR, ensure:
- Code follows Laravel conventions
- Form Requests used for validation
- Service classes used for business logic
- API Resources used for responses
- Tests written and passing
- No N+1 query problems
- Proper error handling
- Authorization checks in place
- Code formatted with Pint
- No hardcoded values
- Proper logging
- Documentation updated
File Organization
Controllers
- Location:
app/Http/Controllers/ - Naming:
PascalCase+Controllersuffix - Example:
ProductController.php
Models
- Location:
app/Models/ - Naming:
PascalCasesingular - Example:
Product.php
Form Requests
- Location:
app/Http/Requests/ - Naming:
PascalCase+ action +Request - Example:
StoreProductRequest.php
API Resources
- Location:
app/Http/Resources/ - Naming:
PascalCase+Resource - Example:
ProductResource.php
Services
- Location:
app/Services/ - Naming:
PascalCase+Service - Example:
ProductService.php
Jobs
- Location:
app/Jobs/ - Naming:
PascalCaseverb phrase - Example:
ProcessProduct.php
Common Patterns
Controller Pattern
<?php
namespace App\Http\Controllers;
use App\Http\Requests\StoreProductRequest;
use App\Http\Resources\ProductResource;
use App\Services\ProductService;
use Illuminate\Http\JsonResponse;
class ProductController extends Controller
{
public function __construct(
private ProductService $productService
) {}
public function store(StoreProductRequest $request): JsonResponse
{
$product = $this->productService->createProduct(
$request->validated(),
$request->user()
);
return response()->json([
'success' => true,
'data' => new ProductResource($product),
'message' => 'Product created successfully'
], 201);
}
}
Service Pattern
<?php
namespace App\Services;
use App\Models\Product;
use Illuminate\Support\Facades\DB;
class ProductService
{
public function createProduct(array $data, User $user): Product
{
return DB::transaction(function () use ($data, $user) {
$product = Product::create([
'user_id' => $user->id,
...$data
]);
// Additional logic
return $product->load(['images', 'category']);
});
}
}
Form Request Pattern
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreProductRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'title' => 'required|string|max:255',
'description' => 'required|string',
'category_id' => 'required|exists:categories,id',
];
}
public function messages(): array
{
return [
'title.required' => 'Product title is required',
];
}
}
Testing Guidelines
Write Tests For
- New features
- Bug fixes
- Critical business logic
- API endpoints
- Services
Test Structure
<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
class ProductTest extends TestCase
{
use RefreshDatabase;
/** @test */
public function it_can_create_a_product()
{
// Arrange
$user = User::factory()->create();
// Act
$response = $this->actingAs($user, 'api')
->postJson('/api/v1/add-product', [
'title' => 'Test Product',
'description' => 'Test Description',
]);
// Assert
$response->assertStatus(201)
->assertJson([
'success' => true,
]);
}
}
What to Avoid
❌ Never Do These:
- NO mass assignment without $fillable
- NO business logic in controllers
- NO inline validation
- NO raw SQL queries (use Eloquent)
- NO N+1 queries
- NO hardcoded values
- NO exposing sensitive data
- NO forgetting transactions
- NO plain passwords (always hash)
- NO skipping authorization