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

Scoutify Laravel Package

matheusmarnt/scoutify

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require matheusmarnt/scoutify
    php artisan scoutify:install
    

    Follow prompts to select Scout driver (Meilisearch, Algolia, Typesense, or Database).

  2. Register Models:

    php artisan scoutify:searchable
    

    Select models to make searchable (or use --all). The command auto-edits model files.

  3. Import Models:

    php artisan scoutify:import
    
  4. Add UI Components to your layout:

    <!-- Desktop trigger -->
    <x-scoutify::gs.trigger class="hidden lg:inline-flex" />
    
    <!-- Mobile trigger -->
    <x-scoutify::gs.trigger-mobile />
    
    <!-- Modal (must be at root level) -->
    {{ $slot }}
    <livewire:scoutify::modal />
    

First Use Case

Trigger the modal with ⌘K (Mac) / Ctrl+K (Windows). Start typing to search across all registered models. Results appear grouped by model type with icons, titles, and subtitles.


Implementation Patterns

Model Registration Workflow

  1. Auto-Discovery: Scoutify scans app/Models/ for Eloquent models. Use --dry-run to preview changes:
    php artisan scoutify:searchable --dry-run
    
  2. Customize Model Methods: Override trait defaults in your model:
    public function globalSearchTitle(): string { return $this->custom_title; }
    public static function globalSearchIcon(): string { return 'ri-file-pdf-fill'; }
    
  3. Batch Updates: Use --all to register all models at once:
    php artisan scoutify:searchable --all
    

Integration with Scout Drivers

  • Meilisearch/Algolia/Typesense: Configure in config/scout.php. Scoutify auto-detects the driver.
  • Database Driver: Use for simple projects or when infix matching is needed (via LIKE queries).

Livewire Component Placement

  • Modal Placement: Must be at the root of your layout, outside collapsible containers (e.g., sidebars, drawers).
  • Trigger Placement: Use <x-scoutify::gs.trigger /> for desktop (lg+) and <x-scoutify::gs.trigger-mobile /> for mobile.

Programmatic Triggering

  • Alpine.js:
    <button x-data @click="$dispatch('scoutify:open')">Search</button>
    
  • Livewire:
    <button wire:click="$dispatchTo('scoutify::modal', 'scoutify:open')">Search</button>
    
  • Vanilla JS:
    window.dispatchEvent(new CustomEvent('scoutify:open'));
    

Authorization Patterns

  1. Default Behavior: Secure-by-default (guests denied, auth users checked via policy).
  2. Per-Model Overrides: Implement HasGlobalSearchVisibility:
    public function globalSearchVisibility(): VisibilityRule
    {
        return VisibilityRule::make()
            ->visibleToGuests()
            ->orWhenAuthenticated()
                ->policy('view')
                ->orPermission('edit-articles');
    }
    
  3. Global Config: Adjust in config/scoutify.php:
    'authorization' => [
        'default' => 'permissive', // 'secure', 'permissive', or 'gate-only'
    ],
    

File Previews

  1. Implement HasGlobalSearchPreview:
    public function globalSearchPreview(): ?PreviewDto
    {
        return PreviewDto::fromDisk('documents', $this->file_path);
    }
    
  2. Handle Downloads: Listen for the scoutify:download event:
    window.addEventListener('scoutify:download', (e) => {
        const a = document.createElement('a');
        a.href = e.detail.url;
        a.download = e.detail.filename;
        a.click();
    });
    

Custom Query Building

Override globalSearchBuilder() for model-specific filters:

public function globalSearchBuilder(Builder $builder, string $query): Builder
{
    return $builder->where('status', 'published')->where('category', 'tech');
}

Gotchas and Tips

Pitfalls

  1. Modal Placement:

    • Issue: Modal fails to initialize if placed inside a collapsed container (e.g., sidebar).
    • Fix: Ensure <livewire:scoutify::modal /> is at the root layout level, outside dynamic containers.
  2. Icon Pack Conflicts:

    • Issue: Short icon names (e.g., user) default to heroicon-o- prefix. If using multiple packs, fully qualify icons (e.g., ri-user-fill).
    • Fix: Override the prefix globally:
      Scoutify::types()->iconPrefix('ri-');
      
  3. Meilisearch Substring Search:

    • Issue: Meilisearch uses prefix search by default. Queries like "ano" in "Mariano" return no results.
    • Fix: Override globalSearchBuilder() to configure attributesToSearchOn or switch to the database driver.
  4. Livewire Event Dispatch:

    • Issue: $dispatch('scoutify:open') fails outside Livewire components.
    • Fix: Use $dispatchTo('scoutify::modal', 'scoutify:open') in Livewire or Alpine/JS for non-Livewire contexts.
  5. Authorization Gaps:

    • Issue: Missing policies for models cause auth checks to fail silently.
    • Fix: Use gate-only mode in config/scoutify.php to enforce policies strictly.
  6. File Preview Permissions:

    • Issue: Preview pane shows unauthorized files if visibility rules aren’t applied.
    • Fix: Ensure the model implements HasGlobalSearchVisibility and the PreviewDto record passes authorization checks.

Debugging Tips

  1. Check Scout Index:

    • Verify models are indexed:
      php artisan scout:index
      
    • For Meilisearch/Algolia, check the dashboard for indexed records.
  2. Livewire Logs:

    • Enable Livewire logging in config/livewire.php:
      'log' => env('LIVEWIRE_LOG', true),
      
    • Check storage/logs/livewire.log for modal initialization errors.
  3. Query Inspection:

    • Override globalSearchBuilder() temporarily to log queries:
      public function globalSearchBuilder(Builder $builder, string $query): Builder
      {
          \Log::info('Scoutify query:', ['query' => $query, 'toSearchableArray' => $builder->toSearchableArray()]);
          return $builder;
      }
      
  4. Event Listener Debugging:

    • Verify the scoutify:download event listener is registered:
      console.log('Listener registered:', window.addEventListener);
      

Configuration Quirks

  1. Dark Mode:

    • Scoutify supports dark mode out of the box. Ensure your Tailwind config includes:
      darkMode: 'class',
      
  2. Translation Overrides:

    • Override default translations in resources/lang/en/scoutify.php:
      return [
          'search_placeholder' => 'Search across all models...',
      ];
      
  3. Recent Searches:

    • History is stored in the session. Clear it via:
      session()->forget('scoutify.recent_searches');
      
  4. Tailwind Overrides:

    • Customize the theme via the fluent API:
      Scoutify::theme()
          ->modalBackground('bg-gray-800')
          ->resultItemHover('hover:bg-gray-700');
      

Extension Points

  1. Custom Result Components:

    • Extend the result item view by publishing the Livewire component:
      php artisan vendor:publish --tag=scoutify-views
      
    • Override resources/views/vendor/scoutify/result-item.blade.php.
  2. Scout Driver Extensions:

    • Add custom drivers by implementing Matheusmarnt\Scoutify\Contracts\ScoutDriver.
  3. Authorization Logic:

    • Extend VisibilityRule for custom conditions:
      VisibilityRule::make()->using(fn($record, $user) => $user->isAdmin());
      
  4. Preview Pane Customization:

    • Override the preview component:
      php artisan vendor:publish --tag=scoutify-views
      
    • Edit resources/views/vendor/scoutify/preview-pane.blade.php.
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