Coding Guidelines
Coding Guidelines
This document outlines the coding standards and best practices for the Inventory Management API project built with PHP 8.2+ and Laravel 12.
π― General Principles
Code Quality
- Write clean, readable, and maintainable PHP code
- Follow the principle of least surprise
- Use meaningful names for variables, functions, classes, and methods
- Keep functions and classes small and focused
- Comment complex logic and business rules using PHPDoc
Performance
- Optimize for database performance
- Use proper Eloquent relationships and eager loading
- Implement efficient caching strategies
- Minimize API response times
π§ PHP & Laravel Standards
Class Structure
- Follow PSR-12 coding standards for all PHP code
- Use strict typing where applicable
- Laravel conventions for naming and structure
- Eloquent best practices for database interactions
<?php
namespace App\Http\Controllers;
use App\Http\Requests\StoreItemRequest;
use App\Http\Requests\UpdateItemRequest;
use App\Http\Resources\ItemResource;
use App\Models\Item;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
/**
* Controller for managing inventory items.
*
* Provides CRUD operations for items with proper validation,
* authorization, and resource transformation.
*/
class ItemController extends Controller
{
/**
* Display a listing of items.
*/
public function index(Request $request): AnonymousResourceCollection
{
$items = Item::with(['partner', 'project', 'country'])
->when($request->has('search'), function ($query) use ($request) {
$query->where('internal_name', 'like', "%{$request->search}%");
})
->paginate(15);
return ItemResource::collection($items);
}
/**
* Store a newly created item.
*/
public function store(StoreItemRequest $request): ItemResource
{
$item = Item::create($request->validated());
return new ItemResource($item->load(['partner', 'project', 'country']));
}
}
Code Organization
- Keep controllers focused - one responsibility per controller
- Use service classes for complex business logic
- Proper naming - follow Laravel naming conventions
- Type hints - use type hints for all method parameters and return types
<?php
// β
Good - Organized imports
// 1. Laravel/Framework imports
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\DB;
// 2. Third-party imports
use Carbon\Carbon;
// 3. Internal imports - Models
use App\Models\Item;
use App\Models\Partner;
// 4. Internal imports - Resources
use App\Http\Resources\ItemResource;
// 5. Internal imports - Requests
use App\Http\Requests\StoreItemRequest;
// 6. Internal imports - Services
use App\Services\ImageProcessingService;
π¨ Laravel Guidelines
Model Design
- Use UUID primary keys for scalability (except User, Language, Country)
- Implement proper relationships
- Use model factories for testing
- Add appropriate validation rules
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
/**
* Item model representing inventory objects.
*
* @property string $id
* @property string $internal_name
* @property string $partner_id
* @property string $project_id
* @property string $country_id
* @property string|null $backward_compatibility
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
*/
class Item extends Model
{
use HasFactory, HasUuids;
/**
* The attributes that are mass assignable.
*/
protected $fillable = [
'internal_name',
'partner_id',
'project_id',
'country_id',
'backward_compatibility',
];
/**
* Get the columns that should receive a unique identifier.
*/
public function uniqueIds(): array
{
return ['id'];
}
/**
* Get the partner that owns the item.
*/
public function partner(): BelongsTo
{
return $this->belongsTo(Partner::class);
}
/**
* Get the project associated with the item.
*/
public function project(): BelongsTo
{
return $this->belongsTo(Project::class);
}
/**
* Get the country associated with the item.
*/
public function country(): BelongsTo
{
return $this->belongsTo(Country::class);
}
/**
* Get the pictures associated with the item.
*/
public function pictures(): HasMany
{
return $this->hasMany(Picture::class);
}
}
Controller Design
<?php
namespace App\Http\Controllers;
use App\Http\Requests\StoreItemRequest;
use App\Http\Requests\UpdateItemRequest;
use App\Http\Resources\ItemResource;
use App\Models\Item;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
/**
* β
Good - Resource controller with proper typing
*/
class ItemController extends Controller
{
public function index(): AnonymousResourceCollection
{
$items = Item::with(['partner', 'project', 'country'])->paginate(15);
return ItemResource::collection($items);
}
public function show(Item $item): ItemResource
{
return new ItemResource($item->load(['partner', 'project', 'country']));
}
public function store(StoreItemRequest $request): ItemResource
{
$item = Item::create($request->validated());
return new ItemResource($item->load(['partner', 'project', 'country']));
}
public function update(UpdateItemRequest $request, Item $item): ItemResource
{
$item->update($request->validated());
return new ItemResource($item->load(['partner', 'project', 'country']));
}
public function destroy(Item $item): JsonResponse
{
$item->delete();
return response()->json(null, 204);
}
}
β Quality Controls
Before submitting code, ensure all quality controls pass:
1. Code Quality
# Run PHP CS Fixer (Pint)
composer ci-lint
# Enhanced linting with arguments
$env:COMPOSER_ARGS="--test"; composer ci-lint
$env:COMPOSER_ARGS="--verbose"; composer ci-lint
# Helper command for linting with arguments
composer ci-lint:with-args --test --verbose
# Run static analysis (if configured)
composer ci-audit
2. Testing
# Run the complete test suite
composer ci-test
# Run specific test types
php artisan test tests/Unit
php artisan test tests/Feature
# Enhanced testing with argument passing
$env:COMPOSER_ARGS="--filter Picture"; composer ci-test
$env:COMPOSER_ARGS="--testsuite=Feature"; composer ci-test
# Helper command for filter-based testing
composer ci-test:filter "YourTestClass"
Enhanced CI Scripts
The project includes enhanced PowerShell scripts in the scripts/
directory:
# Enhanced test execution with flexible arguments
.\scripts\ci-test.ps1
# Test filtering with specialized script
.\scripts\ci-test-with-filter.ps1 "Picture"
# Enhanced linting with configurable options
.\scripts\ci-lint.ps1
# Linting with additional arguments
.\scripts\ci-lint-with-args.ps1 --test --verbose
Features:
- Argument Passing: Support for
COMPOSER_ARGS
environment variable - Error Handling: Improved error reporting and debugging
- Flexible Testing: Filter tests by class, method, or test suite
- Configurable Linting: Multiple validation levels and options
3. Build Verification
# Build frontend assets
composer ci-build
# Reset and seed database
composer ci-reset
composer ci-seed
4. Security & Dependencies
# Check for vulnerabilities
composer ci-audit
# Generate OpenAPI documentation
composer ci-openapi-doc
5. Git Hygiene
# Run all pre-commit checks
composer ci-before:pull-request
# Ensure no uncommitted changes
composer ci-git:assert-no-change
ποΈ Application Architecture
Model Structure Pattern
Each entity follows a consistent Laravel pattern:
app/
βββ Http/
β βββ Controllers/
β β βββ EntityNameController.php # RESTful API controller
β βββ Requests/
β β βββ StoreEntityNameRequest.php # Validation for create
β β βββ UpdateEntityNameRequest.php # Validation for update
β βββ Resources/
β βββ EntityNameResource.php # API response formatting
βββ Models/
β βββ EntityName.php # Eloquent model
database/
βββ factories/
β βββ EntityNameFactory.php # Test data generation
βββ migrations/
β βββ create_entity_names_table.php # Database schema
βββ seeders/
βββ EntityNameSeeder.php # Sample data
tests/
βββ Feature/
β βββ Api/
β βββ EntityName/
β βββ AnonymousTest.php # Unauthenticated access tests
β βββ IndexTest.php # List endpoint tests
β βββ ShowTest.php # Show endpoint tests
β βββ StoreTest.php # Create endpoint tests
β βββ UpdateTest.php # Update endpoint tests
β βββ DestroyTest.php # Delete endpoint tests
βββ Unit/
βββ EntityName/
βββ FactoryTest.php # Factory tests
Adding New Entities
When adding new entities to the API:
- Migration - Create database schema with proper constraints
- Model - Create Eloquent model with relationships and UUIDs
- Factory - Create model factory for testing and seeding
- Seeder - Create seeder for sample data
- Controller - Create RESTful API controller
- Requests - Create form request classes for validation
- Resource - Create API resource for response formatting
- Routes - Add routes to
routes/api.php
- Tests - Add comprehensive test coverage
- Documentation - Update API documentation (auto-generated via Scramble)
Core Entities
Primary Entities
- Items - Central inventory management with complex relationships
- Partners - Museums, institutions, and individuals
- Projects - Collections with launch dates and status management
- Tags - Flexible categorization system with many-to-many relationships
- Pictures - Image management with automatic processing
Reference Data
- Countries - Geographic reference using ISO 3166-1 alpha-3 codes
- Languages - Language reference using ISO 639-1 codes
- Contexts - Content organization and categorization hierarchy
Supporting Models
- Details - Extended metadata and flexible information storage
- ImageUploads - File upload tracking and processing status
- AvailableImages - Image availability and accessibility management
π« Common Pitfalls
Avoid These Mistakes
- Not following Laravel naming conventions
- Missing type hints on method parameters and returns
- Not using proper Eloquent relationships
- Ignoring mass assignment protection
- Not writing comprehensive tests
- Forgetting to run code formatting (Pint)
- Not following PSR-12 coding standards
- Missing PHPDoc documentation
Following these guidelines ensures consistent, maintainable, and high-quality PHP code across the entire API project.