All Projects → liam-wiltshire → Laravel Jit Loader

liam-wiltshire / Laravel Jit Loader

Licence: mit

Projects that are alternatives of or similar to Laravel Jit Loader

Laravel Model Expires
A package to assign expiration dates to Eloquent models.
Stars: ✭ 148 (-29.52%)
Mutual labels:  eloquent, laravel
Laravel Auditing
Record the change log from models in Laravel
Stars: ✭ 2,210 (+952.38%)
Mutual labels:  eloquent, laravel
Pinatra
A PHP copy of Sinatra: a DSL for quickly creating web applications in PHP with minimal effort.
Stars: ✭ 151 (-28.1%)
Mutual labels:  eloquent, laravel
Querybuilderparser
A simple to use query builder for the jQuery QueryBuilder plugin for use with Laravel.
Stars: ✭ 126 (-40%)
Mutual labels:  eloquent, laravel
Cms
Multilingual PHP CMS built with Laravel and bootstrap
Stars: ✭ 2,342 (+1015.24%)
Mutual labels:  eloquent, laravel
Eager Load Pivot Relations
Eager load pivot relations for Laravel Eloquent's BelongsToMany relation.
Stars: ✭ 134 (-36.19%)
Mutual labels:  eloquent, laravel
Rating
Laravel Eloquent Rating allows you to assign ratings to any model.
Stars: ✭ 175 (-16.67%)
Mutual labels:  eloquent, laravel
Searchable
Search/filter functionality for Laravel's Eloquent models
Stars: ✭ 113 (-46.19%)
Mutual labels:  eloquent, laravel
Larapoll
A Laravel package to manage your polls
Stars: ✭ 189 (-10%)
Mutual labels:  eloquent, laravel
Laravel Migrate Fresh
An artisan command to build up a database from scratch
Stars: ✭ 179 (-14.76%)
Mutual labels:  eloquent, laravel
Sieve
A simple, clean and elegant way to filter Eloquent models.
Stars: ✭ 123 (-41.43%)
Mutual labels:  eloquent, laravel
Laravel Computed Properties
Make your accessors smarter
Stars: ✭ 197 (-6.19%)
Mutual labels:  eloquent, laravel
Guardian
Eloquent Guardian is a simple permissions system for your users. While there are many other packages for permissions, this one solves everything in the most eloquent way.
Stars: ✭ 121 (-42.38%)
Mutual labels:  eloquent, laravel
Laravel Deletable
👾 Gracefully restrict deletion of Laravel Eloquent models
Stars: ✭ 137 (-34.76%)
Mutual labels:  eloquent, laravel
Laravel Invoicable
Easy invoice creation for Laravel
Stars: ✭ 118 (-43.81%)
Mutual labels:  eloquent, laravel
Schedule
Schedule is a package that helps tracking schedules for your models. If you have workers in a company, you can set schedules for them and see their availability though the time.
Stars: ✭ 155 (-26.19%)
Mutual labels:  eloquent, laravel
Laravel Settings
Store key value pair in database as settings
Stars: ✭ 107 (-49.05%)
Mutual labels:  eloquent, laravel
Laravel Cacheable
Rinvex Cacheable is a granular, intuitive, and fluent caching system for eloquent models. Simple, but yet powerful, plug-n-play with no hassle.
Stars: ✭ 107 (-49.05%)
Mutual labels:  eloquent, laravel
Eloquent Filter
The Eloquent Filter is a package for filter data of models by the query string. Easy to use and fully dynamic.
Stars: ✭ 175 (-16.67%)
Mutual labels:  eloquent, laravel
Eloquent Hashids
On-the-fly hashids for Laravel Eloquent models. (🍰 Easy & ⚡ Fast)
Stars: ✭ 196 (-6.67%)
Mutual labels:  eloquent, laravel

liam-wiltshire/laravel-jit-loader

liam-wiltshire/laravel-jit-loader is an extension to the default Laravel Eloquent model to 'very lazy eager load' relationships with performance comparable with eager loading.

Installation

liam-wiltshire/laravel-jit-loader is available as a composer package: composer require liam-wiltshire/laravel-jit-loader

Once installed, use the \LiamWiltshire\LaravelJitLoader\Concerns\AutoloadsRelationships trait in your model, or have your models extend the \LiamWiltshire\LaravelJitLoader\Model class instead of the default eloquent model, and JIT loading will be automatically enabled.

Very Lazy Eager Load?

In order to avoid N+1 issues, you'd normally load your required relationships while building your collection:

$books = App\Book::with(['author', 'publisher'])->get();

Or otherwise after the fact, but before use:

$books = App\Book::all();

if ($someCondition) {
    $books->load('author', 'publisher');
}

In some situations however, this may not be possible - perhaps front-end developers are able to make changes to templates without touching the code, or perhaps during development you know don't which relationships you'll need anyway. This change will track if your models belong to a collection, and if they do and a relationship is called that hasn't already been loaded, the relationship will be loaded across the whole collection just in time for use.

Does This Work?

This is used in a number of production applications with no issues. It's also been tested against a (rather constructed) test, pulling out staff, companies and addresses - while this isn't a 'real life' representation, it should give an idea of what it can do:

    public function handle()
    {
        //Count the number of queries
        $querycount = 0;
        DB::listen(function ($query) use (&$querycount) {
            $querycount++;
        });

        $startTime = microtime(true);


        $staff = Staff::where('name', 'LIKE', 'E%')->orWhere('name', 'LIKE', 'P%')->get();

        /**
         * @var Staff $st
         */
        foreach ($staff as $st) {
            /**
             * @var Company $company
             */
            $company = $st->company;
            echo "\n\nName: {$st->name}\n";
            echo "Company Name: {$company->name}\n";
            foreach ($company->address as $address) {
                echo "Addresses: {$address->address_1}, ";
            }
        }

        $endTime = microtime(true);

        echo "\n\n=========================\n\n";
        echo "Queries Run: {$querycount}\n";
        echo "Execution Time: " . ($endTime - $startTime) . "\n";
        echo "Memory:" . memory_get_peak_usage(true)/1024/1024 . "MiB";
        echo "\n\n";
    }

Running this locally against a database with 200 companies, 1157 addresses and 39685 staff:

Without JIT Loading:

Queries Run: 10739
Execution Time: 17.090859889984
Memory: 70MiB

With JIT Loading:

Queries Run: 3
Execution Time: 1.7261669635773
Memory: 26MiB

'Proper' Eager Loading:

Queries Run: 3
Execution Time: 1.659285068512
Memory: 26MiB

Logging

As you can see the different between JIT loading and traditional eager loading is small (c. 0.067 seconds in our above test), so you can likely rely on JIT loader to protect you.

However, if you want to log when the JIT loader is used so that you can do back and correct them later, you can add a $logChannel property to your models to ask the trait to log into that channel as configured in Laravel

class Address extends Model
{
    use AutoloadsRelationships;

    /**
     * @var string
     */
    protected $logChannel = 'jit-logger';

    public function company()
    {
        return $this->belongsTo(Company::class);
    }
}

Limitations

This is an early release based on specific use cases. At the moment the autoloading will only be used when the relationship is loaded like a property e.g. $user->company->name instead of $user->company()->first()->name. I am working on supporting relations loaded in alternate ways, however there is more complexity in that so there isn't a fixed timescale as of yet!

With any eager loading, a sufficiently large collection can cause memory issues. The JIT model specifies a threshold for autoloading. This is set to 6000 by default, but can be changed by overriding the $autoloadThreshold property on a model-by-model basis.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].