Skip to content

bjakushka/laravel-engineering-practices

Repository files navigation

Laravel Engineering Practices

A Laravel project showing modern development practices: testing, code quality tools, and automation

PHPStan Level PHP Version License

What This Project Is About

This is not just another CRUD app. Yes, it's a simple bookmark manager, but the real focus is on how the code is written and maintained:

Key Practices Included

  • [ X ] Testing - Feature and unit tests with PHPUnit
  • [ X ] Static Analysis - PHPStan Level 8 (strictest type checking)
  • [ X ] Code Quality - PHP CS Fixer for consistent formatting
  • [ X ] Docker Setup - Ready-to-use containers for development
  • [ X ] Automation - Makefile and composer scripts for common tasks
  • [ X ] CI/CD - Drone CI pipeline with automated testing and deployment

Perfect For

  • Learning how to set up quality tools in Laravel
  • Starting point for new projects with good practices
  • Portfolio showing you care about code quality
  • Reference when setting up testing or CI/CD

The Application

Simple bookmark manager for "read later" articles. Basic CRUD operations with user authentication.

Why simple? To keep focus on development practices, not complex business logic.


Engineering Practices

1. Testing

Tests are organized by type:

tests/
├── Feature/        # Testing HTTP endpoints and services
├── Unit/           # Testing individual functions

Run tests:

docker exec reading-list-laravel composer test

2. Static Analysis

PHPStan Level 8 checks your code for type errors:

docker exec reading-list-laravel composer static-analysis

3. Code Formatting

PHP CS Fixer keeps code style consistent:

docker exec reading-list-laravel composer cs-check  # Check
docker exec reading-list-laravel composer cs-fix    # Fix

4. Quick Commands

All quality checks at once:

docker exec reading-list-laravel composer code-quality-check

Or use Makefile:

make test    # Run tests
make up      # Start Docker
make down    # Stop Docker

5. CI/CD Pipeline

Drone CI automatically runs tests and deploys on every push to master:

Pipeline steps:

  1. Run tests in isolated container
  2. Build production images (Laravel + Nginx)
  3. Deploy to server with zero downtime
  4. Cleanup old images

Configuration: See .drone.yml for full pipeline setup


Requirements

  • Docker: Ensure Docker Desktop or Docker Engine is installed and running on your system.
  • Docker Compose: Included with Docker Desktop, or install separately if using Docker Engine.
  • Docker Network: By default, the project uses an external network named docker_external. You can customize this (see Network Configuration below).
  • External Nginx (Optional but Recommended for Production/Local Dev): This setup assumes you have an external Nginx instance (or similar reverse proxy) that will forward requests to the reading-list-nginx service running within this project's Docker Compose stack.

Setup and Deployment

Follow these steps to get the project up and running:

  1. Clone the Repository:

    git clone https://github.com/bjakushka/laravel-engineering-practices
    cd laravel-engineering-practices
  2. Build and Run Docker Compose Services:

    NOTE: see section on Network Configuration below if you need to customize the network.

    From the project root directory, execute:

    docker compose up --build -d

    This will build the laravel image, start nginx, laravel.

  3. Install Laravel Dependencies:

    Once the containers are running, install the PHP dependencies:

    docker exec reading-list-laravel composer install
  4. Environment Configuration:

    Create a .env file for your Laravel application.

    cp laravel/.env.example laravel/.env

    Update laravel/.env with your desired settings. Ensure APP_KEY is set (next step).

  5. Generate Laravel Application Key:

    Once the laravel service is running, generate the application key:

    docker exec reading-list-laravel php artisan key:generate
  6. Run Database Migrations:

    Once the application key is generated, run the database migrations:

    docker exec reading-list-laravel php artisan migrate
  7. Create First User (Optional):

    To create your first user account, you can use the artisan command:

    docker exec reading-list-laravel php artisan user:create
  8. External Nginx Configuration (Example for reading-list.test):

    If you are using an external Nginx, configure it to proxy requests to the reading-list-nginx service.

    Example Nginx server block (adjust proxy_pass if your Docker network name is different or if you're not using an external network):

    server {
        listen 80;
        listen 443 ssl;
        server_name reading-list.test;
    
        # SSL configuration (if using HTTPS)
        ssl_certificate /path/to/your/reading-list.test.crt;
        ssl_certificate_key /path/to/your/reading-list.test.key;
    
        location / {
            proxy_pass http://reading-list-nginx:80; # Or http://<reading_list_nginx_ip>:80 if not on same Docker network
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }

    NOTE: For local development, you might need to add reading-list.test to your /etc/hosts file pointing to your Docker host's IP (e.g., 127.0.0.1 reading-list.test).

  9. Trust SSL Certificate (for local HTTPS):

    If you generated a self-signed certificate for reading-list.test, you will need to trust it in your operating system's keychain to avoid browser warnings. (Specific steps vary by OS).

Network Configuration

By default, this project uses an external Docker network named docker_external. You can customize the network name to match your existing infrastructure.

Custom Network Configuration

The project connects to an existing external network (typically where your external nginx runs).

Option 1: Using .env file (Recommended)

Create or edit the .env file in the project root:

# Set your existing network name
NETWORK_NAME=your_existing_network_name

Option 2: Using environment variable

# Temporarily override network name
NETWORK_NAME=your_network_name docker compose up -d

# Or export for session
export NETWORK_NAME=docker_my_external_network
docker compose up -d

Important: The network must already exist (created by your external nginx setup). If you're unsure of the network name, list existing networks:

docker network ls

Restarting External Nginx

After starting or restarting the services, you may need to restart your external nginx to refresh DNS resolution:

docker restart your_external_nginx_container

CI/CD Deployment

The project uses Drone CI for automated testing and deployment.

Initial Setup

  1. Add repository to Drone CI and activate it
  2. Create data directories on production server:
    mkdir -p /opt/reading-list/data/sqlite
    mkdir -p /opt/reading-list/data/storage/{app,framework/{sessions,cache,views},logs}
    chown -R 1000:1000 /opt/reading-list/data
    chmod -R 755 /opt/reading-list/data
  3. Add secrets in Drone CI web interface:
    • test_app_key, test_app_env, test_app_debug, test_db_connection, test_db_database
    • data_path, app_key, app_env, app_debug, app_url, network_name
  4. Push to master branch to trigger pipeline

Pipeline: test → build → deploy → cleanup (keeps last 2 builds for rollback)

Testing

The project uses PHPUnit for testing with a comprehensive test suite covering feature and unit tests.

Running Tests via Command Line

Run all tests:

docker exec reading-list-laravel composer test

Alternative method:

docker exec reading-list-laravel php artisan test

Run specific test files:

docker exec reading-list-laravel php artisan test tests/Feature/Http/Controllers/BookmarksController/IndexTest.php

Run tests with coverage (if configured):

docker exec reading-list-laravel php artisan test --coverage

PhpStorm IDE Configuration

The key is using your Docker Compose service as the PHP interpreter so PhpStorm runs tests inside the container with the correct environment.

To run and debug tests directly from PhpStorm IDE:

1. Configure PHP Interpreter for Docker

  1. File → Settings (or PhpStorm → Preferences on macOS)
  2. PHP → CLI Interpreter
  3. Click "+""From Docker, Vagrant, VM, WSL, Remote..."
  4. Select Docker Compose
  5. Configuration files: ./docker-compose.yml
  6. Service: laravel
  7. PHP executable path: /usr/local/bin/php
  8. Click OK

2. Set up PHPUnit Test Framework

  1. PHP → Test Frameworks
  2. Click "+"PHPUnit by Remote Interpreter
  3. Choose your Docker interpreter from step 1
  4. PHPUnit library:
    • Use Composer autoloader: /var/www/html/vendor/autoload.php
    • Path to PHPUnit: should auto-detect as /var/www/html/vendor/bin/phpunit
  5. Test Runner:
    • Default configuration file: /var/www/html/phpunit.xml
    • Default bootstrap file: /var/www/html/vendor/autoload.php

3. Configure Run/Debug Configuration

  1. Run → Edit Configurations
  2. Click "+"PHPUnit
  3. Name: Laravel Tests
  4. Test scope: Defined in the configuration file
  5. Interpreter: Your Docker interpreter
  6. Working directory: should auto-detect as /var/www/html

4. Running Tests from IDE

  • Run all tests: Right-click on tests folder → Run 'tests'
  • Run specific test: Right-click on test file → Run 'TestName'
  • Run single method: Click gutter icon next to test method
  • Debug tests: Use Debug instead of Run

Additional Tips

  • Path mappings: PhpStorm should auto-detect them, but verify in PHP → Path Mappings
  • Environment variables: Set APP_ENV=testing in run configuration if needed
  • Xdebug: Enable in your Docker PHP configuration for debugging support

Code Quality

The project uses PHP CS Fixer for code formatting and PHPStan for static analysis.

PHP CS Fixer Configuration

Run code formatting:

docker exec reading-list-laravel vendor/bin/php-cs-fixer fix

Useful resources:

About

Production-ready Laravel setup: PHPStan Level 8, comprehensive testing, CI/CD

Topics

Resources

License

Stars

Watchers

Forks