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

Sheets Laravel Package

spatie/sheets

Spatie Sheets lets Laravel apps store and retrieve static content from plain text files. Markdown and front matter work out of the box, with flexible parsing, multiple content collections, indexing, and Eloquent-like casting—ideal for docs sites and blogs.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require spatie/sheets
    

    Publish the config (optional):

    php artisan vendor:publish --provider="Spatie\Sheets\SheetsServiceProvider"
    
  2. Configure Storage: Edit config/sheets.php to define:

    • collections (e.g., ['posts', 'pages'])
    • default_collection (e.g., 'posts')
    • storage (e.g., 'local', 's3') with filesystem disk.
  3. First Use Case: Place a Markdown file (e.g., storage/app/sheets/posts/hello.md) with front matter:

    ---
    title: Hello World
    slug: hello
    ---
    # Welcome!
    

    Retrieve it in a controller:

    use Spatie\Sheets\Facades\Sheets;
    
    public function show(Sheets $sheets) {
        $sheet = $sheets->get('hello'); // Returns a `Sheet` model
        return view('sheet', compact('sheet'));
    }
    

Implementation Patterns

Core Workflows

  1. Collection Management:

    • Define collections in config/sheets.php to organize content (e.g., posts, docs).
    • Dynamically add collections via the Sheets facade:
      Sheets::collection('news')->get('latest');
      
  2. File Parsing:

    • Markdown + Front Matter: Default behavior (uses spatie/array-to-xml and spatie/markdown-toc).
    • Custom Parsers: Extend Spatie\Sheets\Parsers\Parser:
      Sheets::extend('json', function () {
          return new class extends Parser {
              public function parse(string $path): array {
                  return json_decode(file_get_contents($path), true);
              }
          };
      });
      
  3. Caching:

    • Enable caching in config/sheets.php ('cache_enabled' => true) to avoid re-parsing files.
    • Clear cache manually:
      php artisan sheets:clear-cache
      
  4. Dynamic Routes:

    • Use Laravel’s route model binding:
      Route::get('/posts/{sheet}', [SheetController::class, 'show']);
      
      Register the binding in AppServiceProvider:
      Sheets::bind();
      
  5. Search/Indexing:

    • Index sheets for search (e.g., Algolia, Scout):
      Sheets::all()->each(function ($sheet) {
          $sheet->searchableData(); // Override in your Sheet model
      });
      

Integration Tips

  • Frontend Integration: Use Blade directives to render sheets:

    @sheet('home')
        <h1>{{ $sheet->title }}</h1>
        {!! $sheet->contents !!} <!-- Auto-converts Markdown to HTML -->
    @endsheet
    

    (Requires registering the directive in AppServiceProvider.)

  • Validation: Validate front matter in a Sheet model:

    use Spatie\Sheets\Sheet;
    
    class Post extends Sheet {
        protected $rules = [
            'title' => 'required|string|max:255',
            'author' => 'required|string',
        ];
    }
    
  • Testing: Use Sheets::fake() to mock sheets in tests:

    public function test_sheet_retrieval() {
        Sheets::fake([
            'home' => [
                'title' => 'Test',
                'contents' => '# Hello',
            ],
        ]);
    
        $this->assertEquals('Test', Sheets::get('home')->title);
    }
    

Gotchas and Tips

Pitfalls

  1. File Permissions:

    • Ensure the storage directory (e.g., storage/app/sheets) is writable by Laravel.
    • For S3/remote storage, verify IAM permissions and disk configuration.
  2. Front Matter Parsing:

    • YAML front matter must be valid. Invalid YAML throws a Symfony\Component\Yaml\Exception\ParseException.
    • Use an online YAML validator to debug issues.
  3. Caching Quirks:

    • Cache is collection-specific. Clearing one collection (php artisan sheets:clear-cache posts) won’t affect others.
    • Cache keys include the file’s mtime. Changes to files may not reflect immediately if cached.
  4. Route Binding:

    • Ensure your Sheet model’s getRouteKeyName() returns the correct key (e.g., slug):
      public function getRouteKeyName() {
          return $this->slug ?? parent::getRouteKeyName();
      }
      
  5. Markdown Processing:

    • Sheets uses parsedown/parsedown by default. For advanced Markdown (e.g., tables, footnotes), install spatie/markdown:
      composer require spatie/markdown
      
      Then configure in config/sheets.php:
      'markdown' => [
          'parser' => \Spatie\Markdown\Markdown::class,
      ],
      

Debugging Tips

  • Log Parsed Data: Temporarily add this to your Sheet model to inspect parsed content:

    protected static function boot() {
        parent::boot();
        static::retrieved(function ($sheet) {
            \Log::debug('Parsed sheet:', [
                'id' => $sheet->id,
                'data' => $sheet->attributesToArray(),
            ]);
        });
    }
    
  • Check File Paths: Verify files are in the correct location:

    \Log::info('Sheets storage path:', config('sheets.storage'));
    
  • Disable Parsing: To debug raw file content, disable parsing in config/sheets.php:

    'parse_contents' => false,
    

Extension Points

  1. Custom Sheet Models: Extend Spatie\Sheets\Sheet to add logic:

    class BlogPost extends Sheet {
        public function getExcerpt() {
            return Str::limit($this->contents, 200);
        }
    }
    
  2. Event Listeners: Listen for sheet events (e.g., Retrieving, Retrieved):

    Sheets::retrieved(function ($sheet) {
        // Post-retrieval logic
    });
    
  3. Custom Storage: Implement Spatie\Sheets\Storage\StorageInterface for non-filesystem storage (e.g., database):

    class DatabaseStorage implements StorageInterface {
        public function get(string $collection, string $id) {
            return DB::table('sheets')->where('collection', $collection)->where('id', $id)->first();
        }
        // ... other methods
    }
    

    Register it in config/sheets.php:

    'storage' => \App\Sheets\DatabaseStorage::class,
    
  4. Middleware: Apply middleware to sheet retrieval:

    Sheets::retrieving(function ($sheet) {
        if ($sheet->isPrivate()) {
            abort_unless(auth()->check(), 403);
        }
    });
    
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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport