Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Folio Laravel Package

laravel/folio

Laravel Folio is a page-based router for Laravel that lets you define routes by creating files, keeping routing simple and organized. Ideal for building pages quickly with less boilerplate, backed by official Laravel documentation and support.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require laravel/folio
    php artisan folio:install
    

    This creates a folio_pages table and publishes the migration.

  2. Define a Page: Create a page record via Tinker or a seeder:

    use App\Models\Folio\Page;
    
    Page::create([
        'path' => 'about',
        'view' => 'pages.about',
        'title' => 'About Us',
    ]);
    
  3. First Route: Access /about in your browser—Folio automatically maps the path to the view.

  4. Key Files:

    • database/migrations/..._create_folio_pages_table.php
    • app/Models/Folio/Page.php (auto-generated)
    • routes/folio.php (auto-generated, mount with Folio::routes()).

First Use Case: Static Marketing Page

Replace a manual route like:

Route::get('/about', fn () => view('pages.about'));

With a database-driven approach:

  1. Add a record to folio_pages with path = 'about' and view = 'pages.about'.
  2. Mount Folio in routes/web.php:
    \Folio::routes();
    
  3. Access /about—no route definitions needed.

Implementation Patterns

Core Workflow: Page-Centric Routing

  1. Define Pages: Use the folio:make command to scaffold a page model/view:

    php artisan folio:make about --view=pages.about
    

    This creates a Page record and corresponding Blade view.

  2. Dynamic Paths: Use {slug} in path for dynamic routes (e.g., path = 'posts/{slug}'):

    Page::create([
        'path' => 'posts/{slug}',
        'view' => 'posts.show',
    ]);
    

    Access via /posts/laravel-folio-intro.

  3. Route Parameters: Bind parameters in views using $page (auto-injected):

    <h1>{{ $page->title }}</h1>
    <p>{{ $page->content }}</p>
    
  4. Middleware: Assign middleware to pages via the middleware column (e.g., ['auth', 'verified']).


Integration Patterns

  1. With Eloquent: Extend the Page model to add custom logic:

    namespace App\Models\Folio;
    
    use Illuminate\Database\Eloquent\Model;
    use Folio\Folio;
    
    class Page extends Model
    {
        public function getRouteKeyName()
        {
            return 'path';
        }
    
        public function url()
        {
            return route(Folio::name($this));
        }
    }
    
  2. Custom Views: Override the default view resolution by implementing a resolveView method in your Page model:

    protected function resolveView()
    {
        return view('custom.' . $this->view);
    }
    
  3. API Endpoints: Use Folio for API routes by returning JSON in views:

    {{ json_encode(['data' => $page->toArray()]) }}
    

    Or create a dedicated API controller that queries folio_pages.

  4. Multi-Language Support: Use domains or subpaths for locales:

    Page::create([
        'path' => 'es/about',
        'view' => 'pages.es.about',
        'domain' => 'es.example.com',
    ]);
    

Advanced Patterns

  1. Page Versioning: Add a versions table and use middleware to serve A/B variants:

    Page::with(['versions' => function ($query) {
        $query->where('variant', session('ab_test'));
    }])->find($path);
    
  2. Caching: Cache page views with tags:

    Cache::tags(['folio-page-' . $page->id])->put($page->path, $view, now()->addHours(1));
    
  3. Admin Integration: Use Laravel Nova to manage pages:

    // In NovaServiceProvider
    Nova::resources([
        \App\Nova\Folio\Page::class,
    ]);
    
  4. Custom Route Generation: Extend Folio’s URL generation:

    use Folio\Folio;
    
    Folio::extend(function ($app) {
        $app->bind('path', function () {
            return 'custom-prefix';
        });
    });
    

Gotchas and Tips

Common Pitfalls

  1. Route Conflicts:

    • Issue: Folio routes may conflict with traditional Laravel routes if mounted after Route::group.
    • Fix: Mount Folio first in routes/web.php:
      \Folio::routes();
      Route::get('/legacy', ...); // Legacy routes after Folio
      
  2. Slug Resolution:

    • Issue: Slugs like index may not resolve correctly.
    • Fix: Use explicit paths (e.g., path = 'home' instead of path = 'index').
  3. Middleware Order:

    • Issue: Page-specific middleware may not apply due to middleware priority.
    • Fix: Ensure Folio’s middleware is registered after global middleware in app/Http/Kernel.php:
      protected $middlewareGroups = [
          'web' => [
              // Global middleware...
              \Folio\Http\Middleware\HandleFolioRequests::class,
          ],
      ];
      
  4. View Discovery:

    • Issue: Custom views may not be found if the view column uses incorrect paths.
    • Fix: Use absolute paths (e.g., view = 'pages.about' instead of view = 'about').

Debugging Tips

  1. List All Routes: Use the folio:list command to debug route definitions:

    php artisan folio:list
    

    Output includes route names, paths, and middleware.

  2. Check Route Binding: Verify route binding with:

    dd(request()->route()->parameters);
    
  3. Clear Cached Routes: If routes aren’t updating, clear the cache:

    php artisan route:clear
    php artisan cache:clear
    
  4. Log View Resolution: Add debug logs to the resolveView method to trace view paths:

    protected function resolveView()
    {
        \Log::debug('Resolving view for path:', [$this->path, $this->view]);
        return view($this->view);
    }
    

Configuration Quirks

  1. Custom Table Names:

    • Issue: Default folio_pages table name may conflict with existing tables.
    • Fix: Override the table name in config/folio.php:
      'table' => 'custom_page_routes',
      
  2. Domain Routing:

    • Issue: Domain-based routing may not work if the domain column is empty.
    • Fix: Ensure domains are set in the folio_pages table or use middleware to infer domains.
  3. Lazy Loading:

    • Issue: Commands like folio:list may be slow on large datasets.
    • Fix: Use chunking or add indexes to the path column:
      Schema::table('folio_pages', function (Blueprint $table) {
          $table->index('path');
      });
      

Extension Points

  1. Custom Page Models: Extend the Folio\Folio facade to support custom models:

    Folio::extend(function ($app) {
        $app->singleton('folio.page.model', function () {
            return \App\Models\CustomPage::class;
        });
    });
    
  2. Event Listeners: Listen for ViewMatched events to log or modify page requests:

    use Folio\Events\ViewMatched;
    
    ViewMatched::listen(function (ViewMatched $event) {
        \Log::info('Page accessed:', [$event->page->path]);
    });
    
  3. Pipeline Extensions: Add custom pipeline steps for pre/post-processing:

    Folio::pipeline(function ($next) {
        return function ($page) use ($next) {
            // Pre-process page
            $page = $next($page);
            // Post-process page
            return $page;
        };
    });
    
  4. Route Caching: Disable route caching for development:

    Folio::disableRouteCaching();
    

Performance Tips

  1. Indexing: Add indexes to frequently queried columns:

    Schema::table('folio_pages', function (Blueprint $table) {
        $table->index('path');
        $table->index('domain');
    });
    
  2. Eager Loading: Eager-load relationships to avoid N+1 queries:

    Page::with(['versions', 'author'])->
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope