Driver for Laravel Scout search package based on tntsearch

Overview

TNTSearch Driver for Laravel Scout - Laravel 5.3 - 8.0

Backers on Open Collective Sponsors on Open Collective Latest Version on Packagist Software License Build Status Quality Score Total Downloads

This package makes it easy to add full text search support to your models with Laravel 5.3 to 8.0.

Premium products

If you find TNT Search to be one of your valuable assets, take a look at one of our premium products

Support us on Open Collective

Contents

Installation

You can install the package via composer:

composer require teamtnt/laravel-scout-tntsearch-driver

Add the service provider:

// config/app.php
'providers' => [
    // ...
    TeamTNT\Scout\TNTSearchScoutServiceProvider::class,
],

Ensure you have Laravel Scout as a provider too otherwise you will get an "unresolvable dependency" error

// config/app.php
'providers' => [
    // ...
    Laravel\Scout\ScoutServiceProvider::class,
],

Add SCOUT_DRIVER=tntsearch to your .env file

Then you should publish scout.php configuration file to your config directory

php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"

In your config/scout.php add:

'tntsearch' => [
    'storage'  => storage_path(), //place where the index files will be stored
    'fuzziness' => env('TNTSEARCH_FUZZINESS', false),
    'fuzzy' => [
        'prefix_length' => 2,
        'max_expansions' => 50,
        'distance' => 2
    ],
    'asYouType' => false,
    'searchBoolean' => env('TNTSEARCH_BOOLEAN', false),
    'maxDocs' => env('TNTSEARCH_MAX_DOCS', 500),
],

To prevent your search indexes being commited to your project repository, add the following line to your .gitignore file.

/storage/*.index

The asYouType option can be set per model basis, see the example below.

Usage

After you have installed scout and the TNTSearch driver, you need to add the Searchable trait to your models that you want to make searchable. Additionaly, define the fields you want to make searchable by defining the toSearchableArray method on the model:



namespace App;

use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;

class Post extends Model
{
    use Searchable;

    public $asYouType = true;

    /**
     * Get the indexable data array for the model.
     *
     * @return array
     */
    public function toSearchableArray()
    {
        $array = $this->toArray();

        // Customize array...

        return $array;
    }
}

Then, sync the data with the search service like:

php artisan scout:import App\\Post

If you have a lot of records and want to speed it up you can run (note that with this you can no longer use model-relations in your toSearchableArray()):

php artisan tntsearch:import App\\Post

After that you can search your models with:

Post::search('Bugs Bunny')->get();

Scout status

php artisan scout:status

With this simple command you'll get a quick overview of your search indices.

Image of Scout Status Command

Or you can pass a searchable model argument:

php artisan scout:status "App\Models\Post"

Image of Scout Status Command

Constraints

Additionally to where() statements as conditions, you're able to use Eloquent queries to constrain your search. This allows you to take relationships into account.

If you make use of this, the search command has to be called after all queries have been defined in your controller.

The where() statements you already know can be applied everywhere.

namespace App\Http\Controllers;

use App\Post;

class PostController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index(Request $request)
    {
        $post = new Post;

        // filter out posts to which the given topic is assigned
        if($request->topic) {
            $post = $post->whereNotIn('id', function($query){
                $query->select('assigned_to')->from('comments')->where('topic','=', request()->input('topic'));
            });
        }

        // only posts from people that are no moderators
        $post = $post->byRole('moderator','!=');

        // when user is not admin filter out internal posts
        if(!auth()->user()->hasRole('admin'))
        {
            $post= $post->where('internal_post', false);
        }

        if ($request->searchTerm) {
            $constraints = $post; // not necessary but for better readability
            $post = Post::search($request->searchTerm)->constrain($constraints);
        }

        $post->where('deleted', false);

        $post->orderBy('updated_at', 'asc');

        $paginator = $post->paginate(10);
        $posts = $paginator->getCollection();

        // return posts
    }
}

Adding via Query

The searchable() method will chunk the results of the query and add the records to your search index.

$post = Post::find(1);

// You may also add record via collection...
$post->searchable();

// OR

$posts = Post::where('year', '>', '2018')->get();

// You may also add records via collections...
$posts->searchable();

When using constraints apply it after the constraints are added to the query, as seen in the above example.

OrderBy

An orderBy() statement can now be applied to the search query similar to the where() statement.

When using constraints apply it after the constraints are added to the query, as seen in the above example.

Sponsors

Become a sponsor and get your logo on our README on Github with a link to your site. [Become a sponsor]

Credits

Contributors

This project exists thanks to all the people who contribute.

Backers

Thank you to all our backers! 🙏 [Become a backer]

Comments
  • TNTSearch for Million records

    TNTSearch for Million records

    Hi. I have imported ~ million record into tntsearch storage. Now the search is getting more then 10s to show results. How can I speed up?

    PS I have a server with 18 Cores and 64GB RAM and I'm testing there

    I'm using:

    • Laravel 5.7

    • laravel-scout-tntsearch-driver 3.2

    Here is my configs 'tntsearch' => [ 'storage' => storage_path() . '/tntsearch', //place where the index files will be stored 'fuzziness' => env('TNTSEARCH_FUZZINESS', true), 'fuzzy' => [ 'prefix_length' => 2, 'max_expansions' => 50, 'distance' => 3 ], 'asYouType' => true, 'searchBoolean' => env('TNTSEARCH_BOOLEAN', false), ],

    opened by alkhachatryan 27
  • Search optimization

    Search optimization

    Hey! Great plugin, i have implemented it in a laravel project i'm working on, and i've indexed the data using tntsearch:import. It took in total pretty much bang on 1 hour to do 2494456 rows, which was impressive compared to the vanilla scout import command. The model that i'm using is a Product and has many columns in the MySQL database, however, i've stored in the search index only the ID and the name for now (using toSearchableArray on the model)

    However, speed is intermittently faster/slower when testing it out. Some strings i try come back quickly, and more complex words come back slower, usually the longer the product name is (and more complex, like alphanumeric) the slower it'll be.

    Luckily it's still way quicker than plain MySQL text search. Is there anything i can do to speed it up even more though? I assumed that indexing only them two columns should be quick enough, i've not changed any of the default config settings for tntsearch either. For example on timings "HP Pavilion 15-au076sa" 6seconds on average (quite slow) "Hayfever Tablets" 200milliseconds on average (perfect!)

    Hopefully i've included as much information about this as i can that could be useful, hopefully also the import statistic is useful to you guys as i couldn't find any import statistics (from people using using tntsearch:import) in the github issues! Any tips on how to make these searches any faster on the product name?

    Also, is there anyway to only return certain columns from the model when using ::search? At the moment it takes everything, which i think could be slowing it down a little bit too on complex products (like having long descriptions) I tried select and pluck but to no avail. Would this be a factor in slowing it down? Just a thought.

    Thanks!

    opened by MikeSheward 24
  • Declaration of TeamTNT\Scout\Engines\TNTSearchEngine::map($results, $model) must be compatible with Laravel\Scout\Engines\Engine::map(Laravel\Scout\Builder $builder, $results, $model)

    Declaration of TeamTNT\Scout\Engines\TNTSearchEngine::map($results, $model) must be compatible with Laravel\Scout\Engines\Engine::map(Laravel\Scout\Builder $builder, $results, $model)

    Declaration of TeamTNT\Scout\Engines\TNTSearchEngine::map($results, $model) must be compatible with Laravel\Scout\Engines\Engine::map(Laravel\Scout\Builder $builder, $results, $model)

    I am receiving this exception when calling search() on a model.

    I have temporarily fixed this by changing the signature of the map function from public function map($results, $model) to public function map(Builder $builder, $results, $model)

    opened by bradley-varol 18
  • very low import model .

    very low import model .

    Hi ! i'm trying to import différent model , who have différent size , i think the import is very very low ..... more than one hour , for a table with 30k record. it's normal ?

    i have a intel core i7 with ssd and 16GO memory . it's note a hardware issue.

    What do you think ?

    opened by valerogeoffrey 18
  • SQLSTATE[HY000]: General error: 21 library routine called out of sequence

    SQLSTATE[HY000]: General error: 21 library routine called out of sequence

    I receive SQLSTATE[HY000]: General error: 21 library routine called out of sequence when reindexing models. This happens in TNTIndexer.php in saveWordList($stems) function. Anyone has any idea how to fix this?

    opened by jjag3r 17
  • QueryException when when more than 1 model indexed

    QueryException when when more than 1 model indexed

    Hi guys,

    This is a bit strange, as I swear it was working at one point. Now however it seems broken.

    I have 2 models, App\Page & App\Advice - their toSearchableArray both look similar - like below:

    public function toSearchableArray() {
        $search = [
            'title'    => $this->title,
            'category' => $this->category,
            'subject'  => $this->subject,
            'intro'    => strip_tags($this->intro),
            'content'  => strip_tags($this->content),
            'tags'     => is_array($this->tags) ? implode(' ',$this->tags) : ''
        ];
    
        $search[$this->getKeyName()] = $this->getKey();
    
        return $search;
    }
    

    Now I run the command php artisan tntsearch:import App\\Page

    Search the works as I'd expect, returning results no problem for pages (or, if I instead only indexed with App\Advice Advice gets searched fine too)

    However when both are index using the above command, I suddenly start hitting error 500 like the below:

    SQLSTATE[42S22]: Column not found: 1054 Unknown column 'advices.id' in 'where clause' (SQL: select * from `pages` where `pages`.`id` in (20, 18, 1, 19, 13, 24, 27, 12, 10, 26, 17, 32, 15, 14, 35, 3, 33, 34, 44, 7, 4, 38, 5, 2) and `advices`.`id` in (33, 37, 19, 41, 18, 40, 5, 43, 29, 7, 28, 48, 72, 15, 75, 31, 59, 51, 81, 58, 30, 52, 77, 11, 62, 46, 23, 45, 60, 47, 35, 56, 54, 79, 68, 61, 83, 20, 34, 42, 50, 38, 63, 55, 70, 36, 3, 73, 49, 10, 25, 69, 22, 71, 76, 64, 78, 66, 65, 84, 67, 8, 16, 27, 74, 4, 9, 53, 39, 57, 17, 6, 13, 80, 32, 21, 14))
    

    It dies on line 205 on /src/Engines/TNTSearchEngine.php - if that's helpful.

    Is there something I'm missing?

    opened by Cookizza 12
  • leftJoinSub() is not a method in Laravel<5.6

    leftJoinSub() is not a method in Laravel<5.6

    Trying to apply pagination on a query with where clauses results in an error for L5.5 or older. leftJoinSub() is only a method in L5.6.

    Call to undefined method Illuminate\Database\Query\Builder::leftJoinSub()

    opened by pdanny 12
  • SQLSTATE[3D000]: Invalid catalog name: 1046 No database selected?

    SQLSTATE[3D000]: Invalid catalog name: 1046 No database selected?

    I try to use laravel scout in my app its giving errors when i hit the submit button.But when I use tinker its giving me result I changed in TNTSearch.php line 67 sqlite to mysql. Then its giving errors. Any help Thanks

    opened by vipin733 12
  • Use with an external connection on the model

    Use with an external connection on the model

    Hey,

    I have a Customer model as follows:

    <?php
    
    class Customer extends Model {
        use Searchable;
    
        protected $connection = 'external_connection';
    
        public $searchable = [ /* ... */ ];
    }
    

    I then run:

    $ php artisan scout:import App\\Customer
    

    And get the following error:

    SQLSTATE[42S02]: Base table or view not found: 1146 Table 'my-app.customers' doesn't exist
    
    Exception trace:
     () at /Users/Josh/Code/my-app/vendor/teamtnt/tntsearch/src/Indexer/TNTIndexer.php:180
     PDO->query() at /Users/Josh/Code/my-app/vendor/teamtnt/tntsearch/src/Indexer/TNTIndexer.php:180
     TeamTNT\TNTSearch\Indexer\TNTIndexer->run() at /Users/Josh/Code/my-app/vendor/teamtnt/laravel-scout-tntsearch-driver/src/Engines/TNTSearchEngine.php:167
     TeamTNT\Scout\Engines\TNTSearchEngine->initIndex() at /Users/Josh/Code/my-app/vendor/teamtnt/laravel-scout-tntsearch-driver/src/Engines/TNTSearchEngine.php:33
     TeamTNT\Scout\Engines\TNTSearchEngine->update() at /Users/Josh/Code/my-app/vendor/laravel/scout/src/Searchable.php:52
     App\Customer->queueMakeSearchable() at /Users/Josh/Code/my-app/vendor/laravel/scout/src/Searchable.php:35
     Illuminate\Database\Eloquent\Collection->Laravel\Scout\{closure}() at n/a:n/a
     call_user_func_array() at /Users/Josh/Code/my-app/vendor/laravel/framework/src/Illuminate/Support/Traits/Macroable.php:78
     Illuminate\Support\Collection->__call() at /Users/Josh/Code/my-app/vendor/laravel/scout/src/SearchableScope.php:34
     Laravel\Scout\SearchableScope->Laravel\Scout\{closure}() at n/a:n/a
     call_user_func() at /Users/Josh/Code/my-app/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php:378
     Illuminate\Database\Eloquent\Builder->chunk() at /Users/Josh/Code/my-app/vendor/laravel/scout/src/SearchableScope.php:37
     Laravel\Scout\SearchableScope->Laravel\Scout\{closure}() at n/a:n/a
     call_user_func_array() at /Users/Josh/Code/my-app/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php:1412
     Illuminate\Database\Eloquent\Builder->__call() at /Users/Josh/Code/my-app/vendor/laravel/scout/src/Searchable.php:88
     App\Customer::makeAllSearchable() at /Users/Josh/Code/my-app/vendor/laravel/scout/src/Console/ImportCommand.php:43
     Laravel\Scout\Console\ImportCommand->handle() at n/a:n/a
     call_user_func_array() at /Users/Josh/Code/my-app/vendor/laravel/framework/src/Illuminate/Container/Container.php:507
     Illuminate\Container\Container->call() at /Users/Josh/Code/my-app/vendor/laravel/framework/src/Illuminate/Console/Command.php:169
     Illuminate\Console\Command->execute() at /Users/Josh/Code/my-app/vendor/symfony/console/Command/Command.php:256
     Symfony\Component\Console\Command\Command->run() at /Users/Josh/Code/my-app/vendor/laravel/framework/src/Illuminate/Console/Command.php:155
     Illuminate\Console\Command->run() at /Users/Josh/Code/my-app/vendor/symfony/console/Application.php:818
     Symfony\Component\Console\Application->doRunCommand() at /Users/Josh/Code/my-app/vendor/symfony/console/Application.php:186
     Symfony\Component\Console\Application->doRun() at /Users/Josh/Code/my-app/vendor/symfony/console/Application.php:117
     Symfony\Component\Console\Application->run() at /Users/Josh/Code/my-app/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php:111
     Illuminate\Foundation\Console\Kernel->handle() at /Users/Josh/Code/my-app/artisan:35
    

    I've tried importing the same model using the Algolia driver and it imports fine.

    It seems like it's trying to use the default connection instead of the custom connection I have specified on the model.

    Any ideas on how to fix this?

    opened by josh-taylor 11
  • SQLSTATE[HY000]: General error: 5 database is locked

    SQLSTATE[HY000]: General error: 5 database is locked

    Hi there,

    I'm getting the database being locked every day or so. I'm running quite a high traffic site with multiple indeces and they're seemingly auto-locking which is breaking functionality every day..

    Any fix to this?

    opened by MadMikeyB 10
  • Laravel Scout with tntsearch returns empty array

    Laravel Scout with tntsearch returns empty array

    Hey, I have set up Laravel Scout with tntsearch according to the documentation. Only thing I did on top was that I set up database queue driver. When I try to search a model with the ::search all I get is empty array.

    Controller test function:

    public function test()
        {
            $search = Store::search('test')->get();
            return view('test')->with('search', $search);
        }
    

    Store model:

    <?php
    
    namespace App;
    
    use Illuminate\Database\Eloquent\Model;
    use Illuminate\Database\Eloquent\SoftDeletes;
    use Laravel\Scout\Searchable;
    
    class Store extends Model
    {
        use SoftDeletes;
    
        use Searchable;
    
        protected $dates = ['deleted_at'];
    
        protected $fillable = ['name', 'url', 'contact', 'description', 'detail', 'featured', 'network_id', 'currency_id',
            'link', 'comment', 'category_id'];
    
        protected $with = ['favoritable'];
    
        /**
         * Get the indexable data array for the model.
         *
         * @return array
         */
        public function toSearchableArray()
        {
            $array = $this->toArray();
    
            // Customize array...
    
            return $array;
        }
    
        public function categories()
        {
            return $this->belongsToMany('App\Category');
        }
    
        public function network()
        {
            return $this->belongsTo('App\Network');
        }
    
        public function currency()
        {
            return $this->belongsTo('App\Currency');
        }
    
        public function favoritable()
        {
            return $this->belongsTo('App\Favoritable', 'favoritable_id', 'favoritable_id');
        }
    }
    
    

    the result is :

    [ ]
    

    Do you know what can cause this.

    opened by cawrvus 10
  • [Enhancement]Replace getPdo with getReadPdo

    [Enhancement]Replace getPdo with getReadPdo

    https://github.com/teamtnt/laravel-scout-tntsearch-driver/blob/e48c84d29592c7b41d0dcfa6332b0212d8913b4f/src/Console/ImportCommand.php#L44

    When importing, read only access is enough. I think it will be better to replace getPdo with getReadPdo if there is a read-and-write connection.

    In my condition, I run tntsearch:import from a standalone instance with only read only access to my db. But getPdo always returns default pdo (from database write server config)

    opened by pawmaster 0
  • Problem with SQlite / AWS EFS

    Problem with SQlite / AWS EFS

    Hi,

    I have a problem with AWS AFS

    Error

    
    SQLSTATE[HY000]: General error: 10 disk I/O error {"exception":"[object] (PDOException(code: HY000): SQLSTATE[HY000]: General error: 10 disk I/O error at /home/vendor/teamtnt/tntsearch/src/Indexer/TNTIndexer.php:185)
    
    SQLSTATE[HY000]: General error: 5 database is locked {"exception":"[object] (PDOException(code: HY000): SQLSTATE[HY000]: General error: 5 database is locked at /home/vendor/teamtnt/tntsearch/src/Indexer/TNTIndexer.php:420)
    
    

    Have you a solution ?

    Thx

    opened by neopheus 0
  • Incorrect numer of indexed records

    Incorrect numer of indexed records

    Hi,

    When i first time import my record for indexing i get this:

    obraz

    But, when i reimport just after first import, i get:

    obraz

    Why number of indexed records is greater than number of records in database? Is this bug?

    It's related with: https://github.com/teamtnt/tntsearch/issues/60#issuecomment-1140829123 ?

    opened by bbprojectnet 0
  • When search term is part of different words in the index wordlist, only first matching is returned

    When search term is part of different words in the index wordlist, only first matching is returned

    Hey,

    Lets have a look at this case:

    • there are several documents about java, javascript etc..
    • the wordlist table in the search index sqlite has the terms 'java', 'javascript', 'javase' , 'java-interview'
    • asYouType is enabled
    • a user is searching for 'java' and expects to get results for 'java', 'javascript' , etc...

    Only search results for 'java' are returned because TNTSearch::getWordlistByKeyword only returns 'java' because of SELECT * FROM wordlist WHERE term like :keyword ORDER BY length(term) ASC, num_hits DESC LIMIT 1 (l. 308) --> is this by mistake or by intention? In my opinion, when asYouType is enabled the wordlist returned should contain all the words starting with 'java', so the LIMIT 1 could be removed?

    opened by mk-conn 0
  • Search with relationship(s)

    Search with relationship(s)

    Hi, is there any way to use Model::search method via with() function? I'd like to search through my User model which has Role This is my original code: User::with('roles')->paginate($this->paginate)

    So my question is, how can I make it searchable?

    opened by schubertadam 1
Releases(v12.1.0)
Owner
TNT Studio
TNT Studio is a web development company specialized in developing web applications based on latest technologies
TNT Studio
Scout Extended: The Full Power of Algolia in Laravel

Documentation • Community Forum • Stack Overflow • Report a bug • FAQ • Support To dig right in, visit the Scout Extended documentation. Scout Extende

Algolia 378 Dec 1, 2022
Laravel package to search through multiple Eloquent models.

Laravel package to search through multiple Eloquent models. Supports sorting, pagination, scoped queries, eager load relationships and searching through single or multiple columns.

Protone Media 845 Jan 1, 2023
Orbit is a flat-file driver for Laravel Eloquent

Orbit is a flat-file driver for Laravel Eloquent. It allows you to replace your generic database with real files that you can manipulate using the methods you're familiar with.

Ryan Chandler 664 Dec 30, 2022
Google Cloud Storage filesystem driver for Laravel

Google Cloud Storage filesystem driver for Laravel Google Cloud Storage filesystem driver for Laravel. This started as a fork from Superbalist/laravel

Spatie 88 Dec 16, 2022
A Laravel Broadcast Driver for Centrifugo

Laravel Centrifugo Features Compatible with latest Centrifugo 3.0.3 Contains instructions and configuration file for setting up with Laravel Sail Requ

null 7 Jun 29, 2022
SingleStore DB Driver for Laravel

SingleStore DB Driver for Laravel This package provides SingleStore specific schema options, currently supporting keys & shard keys, alongside setting

Charlie Joseph 16 Oct 18, 2022
Neo4j Graph Eloquent Driver for Laravel 5.

NeoEloquent Neo4j Graph Eloquent Driver for Laravel 5. Quick Reference Installation Configuration Models Relationships Edges Migration Schema Aggregat

Vinelab 586 Dec 7, 2022
SEO Helper is a package that provides tools and helpers for SEO (Search Engine Optimization).

SEO Helper By ARCANEDEV© SEO Helper is a package that provides tools and helpers for SEO (Search Engine Optimization). Feel free to check out the rele

ARCANEDEV 301 Nov 25, 2022
Driver for managing cash payments in the Cashier Provider ecosystem

Cash Driver Provider Installation To get the latest version of Cash Driver Provider, simply require the project using Composer: $ composer require cas

Cashier Provider 4 Aug 30, 2022
With Laravel, search and lookup Amazon products easily.

Amazon ECS (E-Commerce Services) Package for Laravel If you need the ability to search Amazon's catalog of products or lookup an individual item with

Joe Dawson 51 Aug 4, 2022
A Laravel 8 and Livewire 2 demo showing how to search and filter by tags, showing article and video counts for each tag (Polymorphic relationship)

Advanced search and filter with Laravel and Livewire A demo app using Laravel 8 and Livewire 2 showing how to implement a list of articles and tags, v

SĂ©rgio Jardim 19 Aug 29, 2022
Simple CRUD + Search using Laravel 8 and Livewire 2

About Laravel Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experie

PowPow 11 Sep 29, 2022
WIRECRUD 9 adalah aplikasi CRUD + Search sederhana yang dibuat menggukana Laravel 9 dan Livewire 2

WIRECRUD 9 adalah aplikasi CRUD + Search sederhana yang dibuat menggukana Laravel 9 dan Livewire 2. Demo bisa dilihat di YouTube Developow Terbuka jika ingin clone apliaksi sederhana ini untuk belajar, bisa ikuti cara-cara berikut ini.

DeveloPow 11 Nov 25, 2022
Laravel IndexNow - Submit webpage updates to search engines

Laravel IndexNow - Submit webpage updates to search engines This packages provides a wrapper to use the IndexNow api in Laravel. This makes indexing n

Laravel Freelancer NL 26 Dec 27, 2022
Send ping to search engine by Index now protocol.

Index now PHP protocol Easy to use protocol that websites can call to notify search engines whenever website contents on any URL is updated or created

Baraja packages 3 Sep 10, 2022
A site which you can apply jobs or search for employees with cool functionalities..

About App An App which you can apply jobs or search for employees with cool functionalities. Some Pics of App Click Image to Zoom in Sign In & Up Empl

Fatih Canbolat 1 Jan 7, 2022
PHP package to help the development of Laravel-based Telegram bots

Laravel-telegram-bot Project description goes here. This description is usually two to three lines long. It should give an overview of what the projec

CC - UFFS 6 May 10, 2021
A simple laravel package to handle multiple key based model route binding

Laravel Model UUID A simple package to handle the multiple key/column based route model binding for laravel package Installation Require the package u

null 13 Mar 2, 2022
Gretel is a Laravel package for adding route-based breadcrumbs to your application.

Gretel Laravel breadcrumbs right out of a fairy tale. Gretel is a Laravel package for adding route-based breadcrumbs to your application. Defining Bre

Galahad 131 Dec 31, 2022