Laravel Framework

Laravel Pint & Code Quality

15 min Lesson 43 of 45

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:
  1. Install Laravel Pint and create a custom configuration
  2. Install Larastan and configure it with level 6
  3. Install IDE Helper and generate helper files
  4. Run all tools and fix reported issues
  5. Add pre-commit hooks for automatic checks
  6. Document your team's coding standards
Exercise 2: Perform a comprehensive code review:
  1. Select an existing controller in your project
  2. Check for proper type hints and return types
  3. Verify proper error handling and validation
  4. Look for N+1 query problems
  5. Suggest improvements for readability
  6. Create a checklist for future code reviews
Exercise 3: Create a CI/CD pipeline:
  1. Set up GitHub Actions or GitLab CI for your Laravel project
  2. Configure automated testing on every push
  3. Add Pint and PHPStan checks to the pipeline
  4. Configure code coverage reporting
  5. Add automated deployment to staging on merge to develop
  6. Set up notifications for build failures