Leaf PHP v5 Documentation

website·Indexed 33 days ago

https://leafphp.dev

A technical reference for building applications with Leaf PHP v5, covering project structures for --lite, --mvc, and --api modes, routing, controller usage, database schema definitions via YAML, and session management.

Tokens
7.1K
Snippets
29
Records
34
Agent score
19%

What's inside Leaf PHP

  1. Implement routing in Leaf PHP v5

    Routing differs by project type. In Basic apps, routes go in index.php. In MVC apps, routes are placed in app/routes/ as partials (files starting with _, e.g., _posts.php), which are automatically loaded.

    Routing Rules:

    • Use the array format ['key' => 'value', ..., handler] only when specifying middleware, names, or module keys. The handler (closure or Controller@method) must always be the last element.
    • In MVC apps, never call app()->run(); the framework handles this automatically.
    • Always return responses (e.g., return response()->json(...)).
    // Basic routes
    app()->get('/home', fn () => response()->json(['status' => 'ok']));
    app()->put('/users/{id}', function ($id) { /* ... */ });
    
    // MVC: Controller routing
    app()->get('/posts', 'PostsController@index');
    
    // Routes with middleware or names
    app()->get('/dashboard', ['middleware' => 'auth.required', 'DashController@index']);
    app()->get('/home', ['name' => 'home', function () { /* ... */ }]);
    
    // Groups and Named Groups
    app()->group('/admin', ['name' => 'admin', 'middleware' => 'auth.required', function () {
        app()->get('/dashboard', ['name' => 'dashboard', 'AdminController@dashboard']); // Route name: admin.dashboard
    }]);
    
    // Resource routes
    app()->resource('/photos', 'PhotosController');
    
    // Generating URLs from names
    app()->route('admin.users.show', ['id' => 5]);
  2. Implement CSRF and XSS protection

    Leaf includes built-in CSRF and XSS protection.

    CSRF Protection:

    • Basic apps: Call app()->csrf().
    • MVC apps: Run leaf install csrf to enable automatically.
    • Blade forms: Use @csrf.
    • JS requests: Use the X-CSRF-Token header.
    • SPAs: Leaf automatically sets an XSRF-TOKEN cookie and accepts the X-XSRF-TOKEN header (disable with 'cookie' => false in config).
    • Tokens: Use csrf()->regenerate() for manual fresh tokens. Set 'rotate' => true in config for single-use tokens.
    • Security: Tokens are derived from APP_KEY. If missing, run php leaf key:generate.

    XSS Protection:

    • Anchor automatically sanitizes all Leaf input. For manual sanitization, use anchor()->sanitize($rawData).
    app()->csrf(); // Basic app
    anchor()->sanitize($rawData); // Manual XSS sanitization
  3. Leaf 5 Development Best Practices and Constraints

    Follow these critical rules to avoid common pitfalls when developing with Leaf 5:

    Project Structure & Configuration

    • Basic Apps: Do not use app/controllers/; routes must reside in index.php.
    • Configuration: Do not use leaf.config.php or a config/ folder; all configuration must be placed in the .env file.
    • MVC Apps: Do not call app()->run() manually; the framework handles this.
    • Environment: Use _env('KEY', 'default') instead of hardcoding credentials.

    Database & Models

    • Migrations: Do not create PHP migration files; use YAML schema files located in app/database/.
    • Schema Columns: Do not manually add id, created_at, or updated_at to schema files; these are added automatically.
    • Foreign Keys: Do not add foreign key columns manually in schema files. Use relationships: - ModelName to generate the FK column automatically. Adding it to both columns and relationships will cause a duplicate column error.
    • Model Tables: Do not define the $table property in a model unless the table name is irregular. Leaf automatically resolves the table name from the class name (e.g., BlogPost becomes blog_posts).
    • Transactions: Do not mix db() and Models in the same transaction as they must share a connection.

    Routing & Requests

    • Route Syntax: Use square brackets in routes only for route parameters (middleware, name, module keys). For plain routes, use: app()->get('/path', 'Controller@method');.
    • Request Handling: request()->next() is consumed on the first read; call it only once per request.
    • File Uploads: Do not use move_uploaded_file() or $_FILES. Use request()->upload('field', 'destination/') for validation and moving files.

    Framework Components

    • Inheritance: Do not extend Leaf\Controller or Leaf\Model directly. Extend the base Controller and Model classes provided with the project.
    • Inertia: Use 303 redirects instead of 302 to prevent method re-use. For 404s, pass the status as the third argument: response()->inertia('not-found', [], 404).
    • Dependencies: Use official Leaf modules instead of third-party packages whenever possible.
  4. Implement Middleware in Leaf PHP

    Leaf supports global middleware, named middleware for specific routes, and built-in authentication middleware. Middleware can also be used to pass data to route handlers via response()->next().
    // Global - runs on every request
    app()->use(function () {
        if (!auth()->user()) response()->exit('Unauthorized', 401);
    });
    
    // Named - register once, use on any route
    app()->registerMiddleware('auth', function () {
        if (!auth()->user()) response()->redirect('/login');
    });
    app()->get('/dash', ['middleware' => 'auth', 'DashController@index']);
    
    // Built-in auth middleware (no registration needed)
    // auth.required: redirects to login if not authenticated
    // auth.guest: redirects away if already authenticated
    // auth.verified: redirects if email not verified
    // is:rolename: checks role
    // can:ability: checks permission
    app()->get('/dash', ['middleware' => 'auth.required', 'DashController@index']);
    app()->get('/admin', ['middleware' => 'is:admin', 'AdminController@index']);
    
    // Middleware class (generate with: leaf g:middleware LogRequest)
    app()->use(LogRequestMiddleware::class);
    
    // Pass data through middleware
    app()->registerMiddleware('loadUser', fn ($next) => response()->next(auth()->user()));
    // In route handler: retrieve via request()->next() (consumed on first read)
    $user = request()->next();
  5. Create views with Blade

    In MVC apps, views are stored in app/views/ and use dot notation for subdirectories (e.g., posts.index maps to app/views/posts/index.blade.php).
    {{-- Layout --}}
    @extends('layouts.app')
    @section('title', 'Page Title')
    @section('content')
        {{ $name }}       {{-- escaped --}}
        {!! $html !!}     {{-- unescaped --}}
        
        @if($condition) ... @endif
        @foreach($items as $item) ... @endforeach
    
        @auth ... @endauth
        @is('admin') ... @endis
        @csrf
        @vite('app.css')
    @endsection
  6. Manage testing and code quality with Alchemy

    Alchemy is a unified tool for testing, linting, and analysis, replacing separate configs for PHPUnit, PHP-CS-Fixer, Rector, and PHPStan. It uses a single alchemy.yml file. Tools are installed lazily upon first use.

    Setup:

    1. Install: leaf install alchemy --dev
    2. Initialize: ./vendor/bin/alchemy init

    Common Commands:

    • composer run test: Run tests (Pest/PHPUnit)
    • composer run lint: Check code style
    • composer run fmt: Fix code style
    • composer run analyse: Run static analysis (PHPStan)
    • composer run refactor: Run Rector refactoring
    • composer run ci: Run all configured CI actions
    • composer run alchemy: Run everything in alchemy.yml
    • alchemy eject: Export to standard config files
    • alchemy switch [provider]: Swap CI provider or test engine
    # Example alchemy.yml snippet
    app:
      - src
    
    tests:
      engine: pest
      parallel: true
      paths: [tests]
    
    lint:
      provider: phpcsfixer
      preset: PSR12
      rules: { single_quote: true }
    
    analyse:
      level: 6
    
    refactor:
      php: '8.2'
      sets: [dead-code, code-quality]
    
    actions:
      provider: github
      run: [lint, tests, analyse, refactor]
  7. Track Errors and Application Journeys with Leaf Crash

    Leaf Crash (leafs/exception v5) records the 'user journey' including router requests, DB queries, log lines, and HTTP calls. It automatically strips secrets (passwords, tokens) and records only prepared SQL without bindings.
    // Add custom journey steps (breadcrumbs)
    crash()->leaveCrumb('coupon applied', 'action', ['total_after' => $total]);
    
    // Capture a report without an exception (e.g., for logic errors)
    crash()->capture('total is 0 but cart has items', [
        'level' => 'warning',
        'peeks' => ['order' => $order],   // bounded, redacted variable snapshots
    ]);
    
    // Measure performance spans
    crash()->span('db: heavy report', fn () => $query->run());
    
    // Set the reporting destination (log file, webhook, Alchemy Cloud)
    crash()->reportTo($reporter);
  8. Implement Billing and Subscriptions (Stripe & Paystack)

    Leaf supports subscription management with a grace period (access remains until the end of the paid period after cancellation). Webhooks are stateless and use the Event object to resolve database entities.
    leaf scaffold:subscriptions
    leaf config:billing
    // Checkout and Plan Management
    billing()->subscribe(['id' => $tierId]);          // returns Session; redirect to ->url()
    billing()->changeSubscription(['id' => $tierId]); // in-place swap
    billing()->portal('/dashboard');                  // hosted billing URL
    
    // User subscription state
    auth()->user()->hasActiveSubscription(); // active, trialing, or cancelled-but-inside-paid-period
    auth()->user()->onGracePeriod();         // cancelled at period end, access still running
    auth()->user()->cancelSubscription();     // at period end; pass false for immediate
    
    // Webhooks
    $event = billing()->webhook();            // verifies signature, returns Event
    $event->renewSubscription();              // on invoice.payment_succeeded
    $event->markSubscriptionPastDue();        // on invoice.payment_failed
    $event->activateSubscription();           // on subscription create/update
    $event->cancelSubscription();             // keeps grace period; pass false to revoke now
  9. Configure frontend tooling in Leaf MVC

    To add view engines and frontend tooling to an MVC application, use the view:install command. If you are using a Basic (--lite) app and need views, you must first run leaf up to scale the project to MVC before installing the view engine.
    leaf view:install --blade|--react|--vue|--svelte|--tailwind|--vite
  10. Manage User Authentication and Roles

    Leaf provides a comprehensive auth system. The users table requires id, email, and a password key. Roles are handled automatically via a leaf_auth_user_roles table created on the first assign() call. For JSON APIs, you can override default middleware failure responses to return JSON instead of redirects.
    leaf install auth
    leaf scaffold:auth   # MVC: generates full auth system
    // Login & Registration
    $ok = auth()->login(['email' => $email, 'password' => $password]);
    $ok = auth()->register(['name' => $n, 'email' => $e, 'password' => $p]);
    
    // Current user
    auth()->user();   // object or null
    auth()->id();     // ID or null
    
    // Roles & permissions
    auth()->createRoles(['admin' => ['edit', 'delete'], 'user' => ['view']]);
    auth()->user()->assign('admin');
    auth()->user()->is('admin');
    auth()->user()->can('edit');
    
    // Configuration
    auth()->config('session', true);        // use sessions (default: JWT)
    auth()->config('db.table', 'admins');
    auth()->config('id.key', 'admin_id');
    auth()->config('hidden', ['password']);
    auth()->dbConnection(db()->connection('mydb'));
    
    // Override default auth redirects for JSON APIs
    auth()->middleware('auth.required', fn () => response()->json(['error' => 'Unauthorized'], 401));
  11. Install Leaf PHP modules

    Use the leaf install command to add functionality. Modules are wired automatically; do not manually configure what the installer handles.
    leaf install auth
    leaf install db
    leaf install mail
    leaf install cors
    leaf install session
    leaf install cache
    leaf install fs@v4
    leaf install fetch
    leaf install lingo       # i18n / translations
    leaf install sitemap
    leaf install queue       # MVC only
    leaf install stripe      # MVC only
    leaf install paystack    # MVC only
  12. Generate controllers, models, and scaffolds

    Leaf provides a set of generator commands (g:) and scaffolds to quickly build application components. Scaffolds auto-detect the frontend (Blade/React/Vue/Svelte) via Inertia setup or can be forced with --scaffold react|vue|svelte|default.
    # Generators
    leaf g:controller Posts              # controller
    leaf g:controller Posts -m           # controller + model
    leaf g:controller Posts -a           # controller + model + schema
    leaf g:controller posts --resource   # full CRUD controller
    leaf g:model Post                    # model only
    leaf g:schema posts                  # schema YAML only
    leaf g:middleware LogRequest         # middleware class
    leaf g:mailer Welcome                # mailer class
    leaf g:job SendEmail                 # queue job
    leaf g:template home                 # view file
    
    # Scaffolds
    leaf scaffold:auth                   # full auth system
    leaf scaffold:subscriptions          # billing/subscriptions
    leaf scaffold:landing-page           # product homepage
    leaf scaffold:waitlist               # waitlist + access middleware
    leaf scaffold:blog                   # markdown blog
    leaf scaffold:contact                # contact form wired to leaf mail
    leaf scaffold:legal                  # privacy policy + terms pages
    leaf scaffold:ai                     # streaming Claude chat (needs ANTHROPIC_API_KEY)
    leaf scaffold:mail                   # install leaf mail + config
    leaf scaffold:shadcn                 # shadcn/ui for react apps