Laravel Pint & Code Quality
Code quality is essential for maintainable applications. Laravel Pint is an opinionated PHP code style fixer built on PHP-CS-Fixer, designed specifically for Laravel projects. Combined with static analysis tools, it ensures your code is clean, consistent, and bug-free.
Introduction to Laravel Pint
What is Laravel Pint?
Laravel Pint is a zero-configuration code style fixer that enforces consistent coding standards across your Laravel application. It comes pre-configured with Laravel's coding style but can be customized to match your team's preferences.
Key Features:
- Zero configuration required - works out of the box
- Built on top of PHP-CS-Fixer
- Supports Laravel, PER, PSR-12, and Symfony presets
- Fast and efficient - only fixes what changed
- IDE and CI/CD integration
Installing and Using Laravel Pint
// Pint comes pre-installed with Laravel 9+
// For older projects, install it:
composer require laravel/pint --dev
// Run Pint to fix code style
./vendor/bin/pint
// Check without fixing (useful for CI)
./vendor/bin/pint --test
// Fix specific files or directories
./vendor/bin/pint app/Models
./vendor/bin/pint app/Http/Controllers/UserController.php
// Preview changes without applying them
./vendor/bin/pint --dry-run
// Show verbose output
./vendor/bin/pint -v
// Use specific preset
./vendor/bin/pint --preset psr12
Configuring Pint
Create a pint.json file in your project root to customize rules:
// pint.json
{
"preset": "laravel",
"rules": {
"simplified_null_return": true,
"braces": false,
"new_with_braces": {
"anonymous_class": true,
"named_class": true
},
"no_unused_imports": true,
"ordered_imports": {
"sort_algorithm": "alpha"
},
"single_quote": true,
"trailing_comma_in_multiline": {
"elements": ["arrays"]
}
},
"exclude": [
"vendor",
"storage",
"bootstrap/cache"
]
}
// Alternative: use PHP configuration
// pint.php
<?php
return [
'preset' => 'laravel',
'rules' => [
'array_syntax' => ['syntax' => 'short'],
'binary_operator_spaces' => [
'default' => 'single_space',
],
'blank_line_after_namespace' => true,
'blank_line_after_opening_tag' => true,
'blank_line_before_statement' => [
'statements' => ['return'],
],
],
];
Git Integration:
Add Pint as a pre-commit hook to automatically fix code style before committing:
# .husky/pre-commit
#!/bin/sh
./vendor/bin/pint --test || (
./vendor/bin/pint
git add .
)
Static Analysis with PHPStan and Larastan
PHPStan performs static analysis to find bugs without running your code. Larastan is a PHPStan wrapper with Laravel-specific rules.
// Install Larastan
composer require larastan/larastan --dev
// Create phpstan.neon configuration
// phpstan.neon
includes:
- vendor/larastan/larastan/extension.neon
parameters:
paths:
- app
- config
- database
- routes
# Level goes from 0 to 9 (strictest)
level: 6
# Ignore specific errors
ignoreErrors:
- '#Call to an undefined method .*::factory\(\)#'
# Check for missing types
checkMissingIterableValueType: false
checkGenericClassInNonGenericObjectType: false
# Custom rules
excludePaths:
- vendor
- storage
- bootstrap/cache
// Run PHPStan
./vendor/bin/phpstan analyse
// Fix what can be fixed automatically
./vendor/bin/phpstan analyse --generate-baseline
// Use memory limit for large projects
./vendor/bin/phpstan analyse --memory-limit=2G
Common PHPStan Issues and Solutions
// Issue: Property has no type or mixed type
// Bad
class User extends Model
{
protected $fillable;
}
// Good
class User extends Model
{
/** @var array<string> */
protected $fillable = ['name', 'email'];
}
// Issue: Method has no return type
// Bad
public function getUsers()
{
return User::all();
}
// Good
public function getUsers(): Collection
{
return User::all();
}
// Issue: Property is never read/written
// Use PHPStan annotations
/** @phpstan-ignore-next-line */
private $unusedProperty;
// Issue: Undefined method on Eloquent model
/** @var \App\Models\User $user */
$user = User::find(1);
$user->posts(); // PHPStan now knows about this relation
// Or use PHPDoc on the model
/**
* @property-read \Illuminate\Database\Eloquent\Collection<Post> $posts
* @method \Illuminate\Database\Eloquent\Relations\HasMany posts()
*/
class User extends Model
{
public function posts()
{
return $this->hasMany(Post::class);
}
}
IDE Helper for Better Autocompletion
Laravel IDE Helper generates PHPDocs for Laravel facades and models to improve IDE autocompletion:
// Install IDE Helper
composer require --dev barryvdh/laravel-ide-helper
// Generate helper files
php artisan ide-helper:generate
php artisan ide-helper:models
php artisan ide-helper:meta
// Auto-generate on composer update
// composer.json
{
"scripts": {
"post-update-cmd": [
"@php artisan ide-helper:generate",
"@php artisan ide-helper:models --nowrite",
"@php artisan ide-helper:meta"
]
}
}
// Add to .gitignore
_ide_helper.php
_ide_helper_models.php
.phpstorm.meta.php
// Generate PHPDoc for models
php artisan ide-helper:models --write
// This adds PHPDoc to your models:
/**
* App\Models\User
*
* @property int $id
* @property string $name
* @property string $email
* @property \Illuminate\Support\Carbon|null $email_verified_at
* @property string $password
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection $notifications
* @property-read \Illuminate\Database\Eloquent\Collection $posts
* @method static \Illuminate\Database\Eloquent\Builder|User whereEmail($value)
* @method static \Illuminate\Database\Eloquent\Builder|User whereName($value)
*/
class User extends Authenticatable
{
// ...
}
IDE Helper Best Practices:
- Generate helper files in development, commit them to version control
- Re-generate after adding new facades, models, or methods
- Use
--nowrite to generate separate PHPDoc files instead of modifying models
- Review generated PHPDocs - sometimes manual correction is needed
Debugging Tools in Laravel
// Laravel Debugbar - powerful debug toolbar
composer require barryvdh/laravel-debugbar --dev
// Telescope - elegant debug assistant for Laravel
composer require laravel/telescope --dev
php artisan telescope:install
php artisan migrate
// Access Telescope
// Visit: http://your-app.test/telescope
// Ray - desktop debugging tool by Spatie
composer require spatie/laravel-ray --dev
// Usage
ray('Debug this');
ray($user, $posts);
ray()->table($users);
ray()->measure(fn() => expensive_operation());
// Clock - debugging helper for Laravel
use Illuminate\Support\Facades\Date;
Date::setTestNow('2024-01-01 12:00:00');
now(); // Returns 2024-01-01 12:00:00
// Query debugging
DB::enableQueryLog();
// Your queries here
dd(DB::getQueryLog());
// Or use query listener
DB::listen(function ($query) {
logger($query->sql, $query->bindings, $query->time);
});
Code Review Best Practices
What to Look For in Code Reviews:
1. Architecture & Design:
- Does the code follow SOLID principles?
- Are responsibilities properly separated?
- Is the code reusable and maintainable?
- Are there any code smells (long methods, god classes)?
2. Laravel Best Practices:
- Proper use of Eloquent relationships
- Correct validation rules
- Authorization with policies
- Database queries are optimized (N+1 prevention)
- Queue jobs for long-running tasks
3. Security:
- No SQL injection vulnerabilities
- CSRF protection in place
- Proper authentication and authorization
- No sensitive data in logs or responses
- Input validation and sanitization
4. Performance:
- Database queries are optimized
- Proper caching strategy
- No unnecessary loops or operations
- Lazy loading vs eager loading
5. Testing:
- Adequate test coverage
- Tests are meaningful and maintainable
- Edge cases are covered
Setting Up Continuous Integration
// GitHub Actions workflow
// .github/workflows/laravel.yml
name: Laravel CI
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
jobs:
laravel-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
extensions: mbstring, xml, bcmath
coverage: xdebug
- name: Copy .env
run: php -r "file_exists('.env') || copy('.env.example', '.env');"
- name: Install Dependencies
run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
- name: Generate key
run: php artisan key:generate
- name: Directory Permissions
run: chmod -R 777 storage bootstrap/cache
- name: Create Database
run: |
mkdir -p database
touch database/database.sqlite
- name: Run Pint
run: ./vendor/bin/pint --test
- name: Run PHPStan
run: ./vendor/bin/phpstan analyse
- name: Execute tests
env:
DB_CONNECTION: sqlite
DB_DATABASE: database/database.sqlite
run: php artisan test --coverage
- name: Upload coverage reports
uses: codecov/codecov-action@v3
Exercise 1: Set up code quality tools:
- Install Laravel Pint and create a custom configuration
- Install Larastan and configure it with level 6
- Install IDE Helper and generate helper files
- Run all tools and fix reported issues
- Add pre-commit hooks for automatic checks
- Document your team's coding standards
Exercise 2: Perform a comprehensive code review:
- Select an existing controller in your project
- Check for proper type hints and return types
- Verify proper error handling and validation
- Look for N+1 query problems
- Suggest improvements for readability
- Create a checklist for future code reviews
Exercise 3: Create a CI/CD pipeline:
- Set up GitHub Actions or GitLab CI for your Laravel project
- Configure automated testing on every push
- Add Pint and PHPStan checks to the pipeline
- Configure code coverage reporting
- Add automated deployment to staging on merge to develop
- Set up notifications for build failures