Skip to main content

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 + Controller suffix
  • Example: ProductController.php

Models

  • Location: app/Models/
  • Naming: PascalCase singular
  • 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: PascalCase verb 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:

  1. NO mass assignment without $fillable
  2. NO business logic in controllers
  3. NO inline validation
  4. NO raw SQL queries (use Eloquent)
  5. NO N+1 queries
  6. NO hardcoded values
  7. NO exposing sensitive data
  8. NO forgetting transactions
  9. NO plain passwords (always hash)
  10. NO skipping authorization