Repository: DarkGhostHunter/Laraload
Branch: master
Commit: 81267de4c731
Files: 21
Total size: 40.2 KB
Directory structure:
gitextract_4flgjxfq/
├── .editorconfig
├── .gitattributes
├── .github/
│ ├── FUNDING.yml
│ ├── dependabot.yml
│ └── workflows/
│ └── php.yml
├── .gitignore
├── .styleci.yml
├── LICENSE
├── README.md
├── composer.json
├── config/
│ └── laraload.php
├── phpunit.xml.dist
├── src/
│ ├── Conditions/
│ │ └── CountRequests.php
│ ├── Events/
│ │ └── PreloadCalledEvent.php
│ ├── Facades/
│ │ └── Laraload.php
│ ├── Http/
│ │ └── Middleware/
│ │ └── LaraloadMiddleware.php
│ ├── Laraload.php
│ └── LaraloadServiceProvider.php
└── tests/
├── Conditions/
│ └── CountRequestTest.php
├── PackageTest.php
└── Stubs/
└── ConditionCallable.php
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
; This file is for unifying the coding style for different editors and IDEs.
; More information at http://editorconfig.org
root = true
[*]
charset = utf-8
indent_size = 4
indent_style = space
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
================================================
FILE: .gitattributes
================================================
# Path-based git attributes
# https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html
# Ignore all test and documentation with "export-ignore".
/.gitattributes export-ignore
/.gitignore export-ignore
/.travis.yml export-ignore
/phpunit.xml.dist export-ignore
/.scrutinizer.yml export-ignore
/tests export-ignore
/.editorconfig export-ignore
/.github export-ignore
================================================
FILE: .github/FUNDING.yml
================================================
# Help me support this package
ko_fi: DarkGhostHunter
custom: ['https://paypal.me/darkghosthunter']
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: composer
directory: "/"
schedule:
interval: daily
time: "09:00"
open-pull-requests-limit: 10
================================================
FILE: .github/workflows/php.yml
================================================
name: PHP Composer
on:
push:
pull_request:
jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
php: [8.0, 7.4]
laravel: [8.*, 7.*, 6.*]
dependency-version: [prefer-stable, prefer-lowest]
include:
- laravel: 8.*
testbench: 6.*
- laravel: 7.*
testbench: 5.*
- laravel: 6.*
testbench: ^4.1
name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }} - ${{ matrix.dependency-version }}
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: mbstring, intl
coverage: xdebug
- name: Cache dependencies
uses: actions/cache@v2
with:
path: ~/.composer/cache/files
key: ${{ runner.os }}-laravel-${{ matrix.laravel }}-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }}
restore-keys: ${{ runner.os }}-laravel-${{ matrix.laravel }}-php-${{ matrix.php }}-composer-
- name: Install dependencies
run: |
composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-progress --no-update
composer update --${{ matrix.dependency-version }} --prefer-dist --no-progress --no-suggest
- name: Run Tests
run: composer run-script test
- name: Upload Coverage to Coveralls
env:
COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COVERALLS_SERVICE_NAME: github
run: |
rm -rf composer.* vendor/
composer require php-coveralls/php-coveralls
vendor/bin/php-coveralls
================================================
FILE: .gitignore
================================================
build
composer.lock
docs
vendor
coverage
.idea
================================================
FILE: .styleci.yml
================================================
preset: laravel
disabled:
- single_class_element_per_statement
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) Italo Israel Baeza Cabrera
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
## This package has been superseeded by [Laragear/Preload](https://github.com/Laragear/Preload).
Please migrate to the new package.
---
# Laraload
Effortlessly create a PHP Preload Script for your Laravel project.
## Requirements
* Laravel 6.x, 7.x or 8.x (Lumen _may_ work too)
* PHP 7.4.3, PHP 8.0 or later
* `ext-opcache`
> The Opcache extension is not enforced by the package. Just be sure to enable it in your project's PHP main process.
## Installation
Call composer and you're done.
```bash
composer require darkghosthunter/laraload
```
## What is Preloading? What does this?
Preloading is a new feature for PHP. It "compiles" a list of files into memory, thus making the application code _fast_ without warming up. For that to work, it needs to read a PHP script that "uploads" these files into memory, at process startup.
This allows the first Requests to avoid cold starts, where all the scripts must be loaded by PHP at that moment. Since this step is moved to the process startup, first Requests become _faster_ as all needed scripts are already in memory.
This package wraps the Preloader package that generates a preload file. Once it's generated, you can point the generated list into your `php.ini`:
```ini
opcache.preload = 'www/app/storage/preload.php';
```
After that, the next time PHP starts, this list of files will be preloaded.
## Usage
By default, this package constantly recreates your preload script each 500 requests in `storage/preload.php`. That's it. But you want the details, don't you?
1. A global terminable middleware checks for non-error response.
2. Then it calls a custom *Condition* class.
3. If the *Condition* evaluates to `true`, the Preload Script is generated.
4. A `PreloadCalledEvent` is fired with the generation status.
## Configuration
Some people may not be happy with the "default" behaviour. Luckily, you can configure your own way to generate the script.
First publish the configuration file:
```bash
php artisan vendor:publish --provider="DarkGhostHunter\Laraload\LaraloadServiceProvider"
```
Let's check the config array:
```php
<?php
return [
'enable' => env('LARALOAD_ENABLE'),
'condition' => \DarkGhostHunter\Laraload\Conditions\CountRequests::class,
'output' => storage_path('preload.php'),
'memory' => 32,
'use_require' => false,
'autoload' => base_path('vendor/autoload.php'),
'ignore-not-found' => true,
];
```
#### Enable
```php
<?php
return [
'enable' => env('LARALOAD_ENABLE'),
];
```
By default, Laraload will be automatically enabled on production environments. You can forcefully enable or disable it using an environment variable set to `true` or `false`, respectively.
```dotenv
LARALOAD_ENABLE=true
```
#### Condition
```php
<?php
return [
'condition' => 'App\MyCustomCondition@handle',
];
```
This package comes with a _simple_ condition class that returns `true` every 500 requests, which triggers the script generation.
You can define your own condition class to generate the Preload script. This will be called after the request is handled to the browser, and it will be resolved by the Service Container.
The condition is called the same way as a Controller action: as an invokable class or using _Class@action_ notation.
#### Output
```php
<?php
return [
'output' => '/var/www/preloads/my_preload.php',
];
```
By default, the script is saved in your storage path, but you can change the filename and path to save it as long PHP has permissions to write on it. Double-check your file permissions.
#### Memory Limit
```php
<?php
return [
'memory' => 64,
];
```
For most applications, 32MB is fine as a preload limit, but you may fine-tune it for your project specifically.
#### Method
```php
<?php
return [
'use_require' => true,
'autoload' => base_path('vendor/autoload.php'),
];
```
Opcache allows to preload files using `require_once` or `opcache_compile_file()`.
Laraload uses `opcache_compile_file()` for better manageability on the files preloaded. Some unresolved links may output warnings at startup, but nothing critical.
Using `require_once` will "execute" all files, resolving all the links (imports, parent classes, traits, interfaces, etc.) before compiling it, and may output heavy errors on files that shouldn't be executed. Depending on your application, you may want to use one over the other.
If you plan use `require_once`, ensure you have set the correct path to the Composer Autoloader, since it will be used to resolve classes, among other files.
### Ignore not found files
```php
<?php
return [
'ignore-not-found' => true,
];
```
Version 2.1.0 and onward ignores non-existent files by default. This may work for files created by Laravel at runtime and actively cached by Opcache, but that on deployment are absent, like [real-time facades](https://laravel.com/docs/facades#real-time-facades).
You can disable this for any reason, which will throw an Exception if any file is missing, but is recommended leaving it alone unless you know what you're doing.
### Include & Exclude directories
For better manageability, you can now append or exclude files from directories using the [Symfony Finder](https://symfony.com/doc/current/components/finder.html), which is included in this package, to retrieve a list of files inside of them with better filtering options.
To do so, add an `array` of directories, or register a callback receiving a Symfony Finder instance to further filter which files you want to append or exclude. You can do this in your App Service Provider by using the `Laravel` facade (or injecting Laraload).
```php
use Symfony\Component\Finder\Finder;
use Illuminate\Support\ServiceProvider;
use DarkGhostHunter\Laraload\Facades\Laraload;
class AppServiceProvider extends ServiceProvider
{
// ...
public function boot()
{
Laraload::append(function (Finder $find) {
$find->in('www/app/vendor/name/package/src')->name('*.php');
});
Laraload::exclude(function (Finder $find) {
$find->in('www/app/resources/views')->name('*.blade.php');
});
}
}
```
### FAQ
* **Can I disable Laraload?**
[Yes.](#enable)
* **Do I need to restart my PHP Server to pick up the changes?**
Absolutely. Generating the script is not enough, PHP won't pick up the changes if the script path is empty or the PHP process itself is not restarted **completely**. You can schedule a server restart with CRON or something.
* **The package returns errors when I used it!**
Check you're using the latest PHP stable version (critical), and Opcache is enabled. Also, check your storage directory is writable.
As a safe-bet, you can use the safe preloader script in `darkghosthunter/preloader/helpers/safe-preloader.php` and debug the error.
If you're sure this is an error by the package, [open an issue](https://github.com/DarkGhostHunter/Laraload/issues/new) with full details and stack trace. If it's a problem on the Preloader itself, [issue it there](https://github.com/DarkGhostHunter/Preloader/issues).
* **Why I can't use something like `php artisan laraload:generate` instead? Like a [Listener](https://laravel.com/docs/events) or [Scheduler](https://laravel.com/docs/scheduling)?**
Opcache is not enabled when using PHP CLI, and if it is, it will gather wrong statistics. You must let the live application generate the list automatically _on demand_.
* **Does this excludes the package itself from the list?**
It does not: since the underlying Preloader package may be not heavily requested, it doesn't matter if its excluded or not. The files in Laraload are also not excluded from the list, since these are needed to trigger the Preloader itself without hindering performance.
* **I activated Laraload but my application still doesn't feel _fast_. What's wrong?**
Laraload creates a preloading script, but **doesn't load the script into Opcache**. Once the script is generated, you must include it in your `php.ini` - currently there is no other way to do it. This will take effect only at PHP process startup.
If you still _feel_ your app is slow, remember to benchmark your app, cache your config and views, check your database queries and API calls, and queue expensive logic, among other things. You can also use [Laravel Octane](https://github.com/laravel/octane) on [RoadRunner](https://roadrunner.dev/).
* **How the list is created?**
Basically: the most hit files in descending order. Each file consumes memory, so the list is _soft-cut_ when the files reach a given memory limit (32MB by default).
* **You said "_soft-cut_", why is that?**
Each file is loaded using `opcache_compile_file()`. If the last file is a class with links outside the list, PHP will issue some warnings, which is normal and intended, but it won't compile the linked files if these were not added before.
* **Can I just put all the files in my project?**
You shouldn't. Including all the files of your application may have diminishing returns compared to, for example, only the most requested. You can always benchmark your app yourself to prove this is wrong for your exclusive case.
* **Can I use a Closure for my condition?**
No, you must use your default condition class or your own class, or use `Class@method` notation.
* **Can I deactivate the middleware? Or check only XXX status?**
Nope. If you are looking for total control, [use directly the Preloader package](https://github.com/DarkGhostHunter/Preloader/).
* **Does the middleware works on unit testing?**
Nope. The middleware is not registered if the application is running under Unit Testing environment.
* **How can I know when a Preload script is successfully generated?**
When the Preload script is called, you will receive a `PreloadCalledEvent` instance with the compilation status (`true` on success, `false` on failure). You can [add a Listener](https://laravel.com/docs/events#registering-events-and-listeners) to dispatch an email or a Slack notification.
If there is a bigger problem, your application logger will catch the exception.
* **Why now I need to use a callback to append/exclude files, instead of a simple array of files?**
This new version uses Preloader 2, which offers greater flexibility to handle files inside a directory. This approach is incompatible with just issuing directly an array of files, but is more convenient in the long term. Considering that appending and excluding files mostly requires pin-point precision, it was decided to leave it as method calls for this kind of flexibility.
* **How can I change the number of hits, cache or cache key for the default condition?**
While I encourage you to create your own condition, you can easily change them by adding a [container event](https://laravel.com/docs/8.x/container#container-events) to your `AppServiceProvider.php`, under the `register()` method.
```php
$this->app->when(\DarkGhostHunter\Laraload\Conditions\CountRequests::class)
->needs('$hits')
->give(1500);
```
## License
This package is licenced by the [MIT License](LICENSE).
================================================
FILE: composer.json
================================================
{
"name": "darkghosthunter/laraload",
"description": "Effortlessly make a Preload script for your Laravel application.",
"keywords": [
"darkghosthunter",
"laraload"
],
"homepage": "https://github.com/darkghosthunter/laraload",
"license": "MIT",
"type": "library",
"authors": [
{
"name": "Italo Israel Baeza Cabrera",
"email": "darkghosthunter@gmail.com",
"role": "Developer"
}
],
"require": {
"php": "^7.4.3||^8.0.2",
"illuminate/support": "^6.0||^7.0||^8.0",
"illuminate/http": "^6.0||^7.0||^8.0",
"illuminate/events": "^6.0||^7.0||^8.0",
"darkghosthunter/preloader": "^2.2.0",
"symfony/finder": "^4.3||^5.0"
},
"require-dev": {
"orchestra/testbench": "^4.1||^5.0||^6.0",
"phpunit/phpunit": "^9.3",
"mockery/mockery": "^1.4",
"orchestra/canvas": "^4.0||^5.0||^6.0"
},
"autoload": {
"psr-4": {
"DarkGhostHunter\\Laraload\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests"
}
},
"scripts": {
"test": "vendor/bin/phpunit --coverage-clover build/logs/clover.xml",
"test-coverage": "vendor/bin/phpunit --coverage-html coverage"
},
"config": {
"sort-packages": true
},
"extra": {
"laravel": {
"providers": [
"DarkGhostHunter\\Laraload\\LaraloadServiceProvider"
],
"aliases": {
"Laraload": "DarkGhostHunter\\Laraload\\Facades\\Laraload"
}
}
}
}
================================================
FILE: config/laraload.php
================================================
<?php
return [
/*
|--------------------------------------------------------------------------
| Main Switch
|--------------------------------------------------------------------------
|
| Laraload detects if the environment is production and automatically runs
| when under it. You can forcefully disable o enable it. Laraload doesn't
| runs if your app is running unit tests, don't worry about disabling it.
|
| Supported: "null", "true", "false".
|
*/
'enable' => env('LARALOAD_ENABLE'),
/*
|--------------------------------------------------------------------------
| Condition logic
|--------------------------------------------------------------------------
|
| The custom condition logic you want to execute to generate (or not) the
| Preload script. You can use any class using it's name, or Class@method
| notation. This will be executed using the Service Container's "call".
|
*/
'condition' => \DarkGhostHunter\Laraload\Conditions\CountRequests::class,
/*
|--------------------------------------------------------------------------
| Output
|--------------------------------------------------------------------------
|
| Once the Preload script is generated, it will written to the storage
| path of your application, since it should have permission to write.
| You can change the script output for anything as long is writable.
|
*/
'output' => storage_path('preload.php'),
/*
|--------------------------------------------------------------------------
| Memory Limit
|--------------------------------------------------------------------------
|
| The Preloader script can be configured to handle a limited number of
| files based on their memory consumption. The default is a safe bet
| for most apps, but you can change it for your app specifically.
|
*/
'memory' => 32,
/*
|--------------------------------------------------------------------------
| Upload method
|--------------------------------------------------------------------------
|
| Opcache supports preloading files by using `require_once` (which executes
| and resolves each file link), and `opcache_compile_file` (which not). If
| you want to use require ensure the Composer Autoloader path is correct.
|
*/
'use_require' => false,
'autoload' => base_path('vendor/autoload.php'),
/*
|--------------------------------------------------------------------------
| Ignore Not Found
|--------------------------------------------------------------------------
|
| Sometimes Opcache will include in the list files that are generated by
| Laravel at runtime which don't exist when deploying the application.
| To avoid errors on preloads, we can tell Preloader to ignore them.
|
*/
'ignore-not-found' => true,
];
================================================
FILE: phpunit.xml.dist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/autoload.php"
backupGlobals="false"
backupStaticAttributes="false"
colors="true"
verbose="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false">
<testsuites>
<testsuite name="Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">src/</directory>
<exclude>
<file>src/LaraloadServiceProvider.php</file>
</exclude>
</whitelist>
</filter>
<logging>
<log type="tap" target="build/report.tap"/>
<log type="junit" target="build/report.junit.xml"/>
<log type="coverage-html" target="build/coverage" charset="UTF-8" yui="true" highlight="true"/>
<log type="coverage-text" target="build/coverage.txt"/>
<log type="coverage-clover" target="build/logs/clover.xml"/>
</logging>
</phpunit>
================================================
FILE: src/Conditions/CountRequests.php
================================================
<?php
namespace DarkGhostHunter\Laraload\Conditions;
use Illuminate\Contracts\Cache\Repository as Cache;
class CountRequests
{
/**
* Cache repository
*
* @var \Illuminate\Contracts\Cache\Repository
*/
protected Cache $cache;
/**
* Number of hits to
*
* @var int
*/
protected int $hits;
/**
* @var string
*/
protected string $cacheKey;
/**
* CountRequest constructor.
*
* @param \Illuminate\Contracts\Cache\Repository $cache
* @param int $hits
* @param string $cacheKey
*/
public function __construct(Cache $cache, int $hits = 500, string $cacheKey = 'laraload|request_hits')
{
$this->cache = $cache;
$this->hits = $hits;
$this->cacheKey = $cacheKey;
}
/**
* Recreates the Preload script each given number of requests.
*
* @return bool
*/
public function __invoke(): bool
{
// Increment the count by one. If it doesn't exists, we will start with 1.
$count = $this->cache->increment($this->cacheKey);
// Each number of hits return true
if ($count && $count % $this->hits === 0) {
$this->cache->set($this->cacheKey, 0);
return true;
}
return false;
}
}
================================================
FILE: src/Events/PreloadCalledEvent.php
================================================
<?php
namespace DarkGhostHunter\Laraload\Events;
class PreloadCalledEvent
{
/**
* Generation status
*
* @var bool true on success, false on failure
*/
public bool $success;
/**
* PreloadCalledEvent constructor.
*
* @param bool $success
*/
public function __construct(bool $success)
{
$this->success = $success;
}
}
================================================
FILE: src/Facades/Laraload.php
================================================
<?php
namespace DarkGhostHunter\Laraload\Facades;
use Illuminate\Support\Facades\Facade;
/**
* @method static void append(array|string|callable $directories)
* @method static void exclude(array|string|callable $directories)
* @method static bool generate()
*/
class Laraload extends Facade
{
/**
* @inheritDoc
*/
protected static function getFacadeAccessor()
{
return \DarkGhostHunter\Laraload\Laraload::class;
}
}
================================================
FILE: src/Http/Middleware/LaraloadMiddleware.php
================================================
<?php
namespace DarkGhostHunter\Laraload\Http\Middleware;
use Closure;
use DarkGhostHunter\Laraload\Laraload;
use Illuminate\Config\Repository as Config;
use Illuminate\Container\Container;
class LaraloadMiddleware
{
/**
* @var \Illuminate\Config\Repository
*/
protected Config $config;
/**
* Application container instance.
*
* @var \Illuminate\Container\Container
*/
protected Container $container;
/**
* CountRequest constructor.
*
* @param \Illuminate\Config\Repository $config
*/
public function __construct(Config $config)
{
$this->container = Container::getInstance();
$this->config = $config;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle($request, Closure $next)
{
return $next($request);
}
/**
* Perform any final actions for the request lifecycle.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* @param \Symfony\Component\HttpFoundation\Response $response
*
* @return void
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
public function terminate($request, $response)
{
if ($this->responseNotError($response) && $this->conditionIsTrue()) {
$this->container->make(Laraload::class)->generate();
}
}
/**
* Returns if the Response is anything but an error or an invalid response.
*
* @param \Psr\Http\Message\ResponseInterface|\Symfony\Component\HttpFoundation\Response $response
*
* @return bool
*/
protected function responseNotError($response): bool
{
return $response->getStatusCode() < 400;
}
/**
* Checks if the given condition logic is true or false.
*
* @return bool
*/
protected function conditionIsTrue(): bool
{
return (bool)$this->container->call($this->config->get('laraload.condition'), [], '__invoke');
}
}
================================================
FILE: src/Laraload.php
================================================
<?php
namespace DarkGhostHunter\Laraload;
use DarkGhostHunter\Preloader\Preloader;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Contracts\Config\Repository as Config;
class Laraload
{
/**
* Configuration array.
*
* @var array
*/
protected array $config;
/**
* Preloader instance.
*
* @var \DarkGhostHunter\Preloader\Preloader
*/
protected Preloader $preloader;
/**
* Event Dispatcher.
*
* @var \Illuminate\Contracts\Events\Dispatcher
*/
protected Dispatcher $dispatcher;
/**
* Callback to use to append files.
*
* @var callable
*/
protected $append;
/**
* Callback to use to exclude files.
*
* @var callable
*/
protected $exclude;
/**
* Laraload constructor.
*
* @param \Illuminate\Contracts\Config\Repository $config
* @param \Illuminate\Contracts\Events\Dispatcher $dispatcher
* @param \DarkGhostHunter\Preloader\Preloader $preloader
*/
public function __construct(Config $config, Dispatcher $dispatcher, Preloader $preloader)
{
$this->config = $config->get('laraload');
$this->preloader = $preloader;
$this->dispatcher = $dispatcher;
}
/**
* Registers a callback to use to append files to the Preloader.
*
* @param array|string|callable $append
*
* @return void
*/
public function append($append): void
{
$this->append = $append;
}
/**
* Registers a callback to use to exclude files from the Preloader.
*
* @param array|string|callable $exclude
*
* @return void
*/
public function exclude($exclude): void
{
$this->exclude = $exclude;
}
/**
* Generates the Preloader Script.
*
* @return bool
*/
public function generate(): bool
{
$preloader = $this->preloader
->ignoreNotFound($this->config['ignore-not-found'])
->memoryLimit($this->config['memory'])
->exclude($this->exclude)
->append($this->append);
if ($this->config['use_require']) {
$preloader->useRequire($this->config['autoload']);
}
$this->dispatcher->dispatch(new Events\PreloadCalledEvent(
$result = $preloader->writeTo($this->config['output'])
));
return $result;
}
}
================================================
FILE: src/LaraloadServiceProvider.php
================================================
<?php
namespace DarkGhostHunter\Laraload;
use Illuminate\Config\Repository;
use Illuminate\Contracts\Http\Kernel;
use Illuminate\Support\ServiceProvider;
use DarkGhostHunter\Preloader\Preloader;
use DarkGhostHunter\Laraload\Http\Middleware\LaraloadMiddleware;
class LaraloadServiceProvider extends ServiceProvider
{
/**
* Register the application services.
*
* @return void
*/
public function register()
{
$this->mergeConfigFrom(__DIR__ . '/../config/laraload.php', 'laraload');
$this->app->singleton(Preloader::class, fn() => Preloader::make());
$this->app->singleton(Laraload::class);
}
/**
* Bootstrap the application services.
*
* @param \Illuminate\Config\Repository $config
* @param \Illuminate\Contracts\Http\Kernel $kernel
*
* @return void
*/
public function boot(Repository $config, Kernel $kernel)
{
// We will only register the middleware if not Running Unit Tests
if ($this->shouldRun($config)) {
$kernel->pushMiddleware(LaraloadMiddleware::class);
}
if ($this->app->runningInConsole()) {
$this->publishes([__DIR__ . '/../config/laraload.php' => config_path('laraload.php')], 'config');
}
}
/**
* Checks if Laraload should run.
*
* @param \Illuminate\Config\Repository $config
*
* @return bool
*
* @codeCoverageIgnore
*/
protected function shouldRun(Repository $config): bool
{
// If it's null run only on production, otherwise the developer decides.
return $config->get('laraload.enable') ?? $this->app->environment('production');
}
}
================================================
FILE: tests/Conditions/CountRequestTest.php
================================================
<?php
namespace Tests\Conditions;
use Exception;
use Illuminate\Contracts\Cache\Repository;
use Orchestra\Testbench\TestCase;
use Tests\Stubs\ConditionCallable;
use Illuminate\Contracts\Http\Kernel;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Event;
use DarkGhostHunter\Laraload\Laraload;
use DarkGhostHunter\Preloader\Preloader;
use DarkGhostHunter\Laraload\LaraloadServiceProvider;
use DarkGhostHunter\Laraload\Conditions\CountRequests;
use DarkGhostHunter\Laraload\Events\PreloadCalledEvent;
use DarkGhostHunter\Laraload\Facades\Laraload as LaraloadFacade;
use DarkGhostHunter\Laraload\Http\Middleware\LaraloadMiddleware;
class CountRequestTest extends TestCase
{
protected function getPackageProviders($app)
{
return [LaraloadServiceProvider::class];
}
protected function getPackageAliases($app)
{
return [
'Laraload' => LaraloadFacade::class
];
}
public function testReaches500AndResets()
{
$cache = $this->mock(Repository::class);
$cache->shouldReceive('increment')->with('laraload|request_hits')
->andReturn(500);
$cache->shouldReceive('set')->with('laraload|request_hits', 0)
->andReturnNull();
(new CountRequests($cache))();
}
public function testUsesNonDefaultConfig()
{
$cache = $this->mock(Repository::class);
$cache->shouldReceive('increment')->with('foo')
->andReturn(6000);
$cache->shouldReceive('set')->with('foo', 0)
->andReturnNull();
(new CountRequests($cache, 6000, 'foo'))();
}
}
================================================
FILE: tests/PackageTest.php
================================================
<?php
namespace Tests;
use Exception;
use Orchestra\Testbench\TestCase;
use Tests\Stubs\ConditionCallable;
use Illuminate\Contracts\Http\Kernel;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Event;
use DarkGhostHunter\Laraload\Laraload;
use DarkGhostHunter\Preloader\Preloader;
use DarkGhostHunter\Laraload\LaraloadServiceProvider;
use DarkGhostHunter\Laraload\Conditions\CountRequests;
use DarkGhostHunter\Laraload\Events\PreloadCalledEvent;
use DarkGhostHunter\Laraload\Facades\Laraload as LaraloadFacade;
use DarkGhostHunter\Laraload\Http\Middleware\LaraloadMiddleware;
class PackageTest extends TestCase
{
protected function getPackageProviders($app)
{
return [LaraloadServiceProvider::class];
}
protected function getPackageAliases($app)
{
return [
'Laraload' => LaraloadFacade::class
];
}
public function testPublishesConfig()
{
$this->artisan('vendor:publish', [
'--provider' => 'DarkGhostHunter\Laraload\LaraloadServiceProvider',
])
->execute();
$this->assertFileExists(base_path('config/laraload.php'));
$this->assertFileEquals(base_path('config/laraload.php'), __DIR__ . '/../config/laraload.php');
unlink(base_path('config/laraload.php'));
}
public function testDoesntRegisterTerminableMiddlewareInTesting()
{
$this->assertFalse(
$this->app[Kernel::class]->hasMiddleware(LaraloadMiddleware::class)
);
}
public function testDoesntWorkWithErrorResponse()
{
$condition = $this->mock(CountRequests::class);
$this->app[Kernel::class]->pushMiddleware(LaraloadMiddleware::class);
$condition->shouldNotReceive('__invoke');
Route::get('/test', function () {
throw new Exception;
});
$condition->shouldReceive('__invoke');
$this->get('/test')->assertStatus(500);
}
public function testReachesCallable()
{
$condition = $this->mock(CountRequests::class);
$laraload = $this->mock(Laraload::class);
$this->app[Kernel::class]->pushMiddleware(LaraloadMiddleware::class);
Route::get('/test', function () {
return 'ok';
});
$condition->shouldReceive('__invoke')
->andReturnTrue();
$laraload->shouldReceive('generate')
->andReturnTrue();
$this->get('/test')->assertSee('ok');
}
public function testCallableWithMethod()
{
$this->app[Kernel::class]->pushMiddleware(LaraloadMiddleware::class);
$laraload = $this->mock(Laraload::class);
$laraload->shouldReceive('generate')
->andReturnTrue();
$this->app->make('config')->set('laraload.condition', ConditionCallable::class . '@handle');
Route::get('/test', function () {
return 'ok';
});
$this->get('/test')->assertSee('ok');
$this->assertEquals(true, ConditionCallable::$called);
}
public function testCallableWithMethodAndParameters()
{
$laraload = $this->mock(Laraload::class);
$this->app[Kernel::class]->pushMiddleware(LaraloadMiddleware::class);
$laraload->shouldReceive('generate')
->andReturnTrue();
$this->app->make('config')->set(
'laraload.condition', ConditionCallable::class . '@handle');
Route::get('/test', function () {
return 'ok';
});
$this->get('/test')->assertSee('ok');
$this->assertTrue(ConditionCallable::$called);
}
public function testConditionWorks()
{
$condition = $this->mock(CountRequests::class);
$laraload = $this->mock(Laraload::class);
$this->app[Kernel::class]->pushMiddleware(LaraloadMiddleware::class);
$laraload->shouldReceive('generate')
->andReturnTrue();
$condition->shouldReceive('__invoke')
->withNoArgs()
->andReturnTrue();
$this->app->make('config')->set('laraload.condition', CountRequests::class);
Route::get('/test', function () {
return 'ok';
});
$this->get('/test')->assertSee('ok');
}
public function testConditionsCallsLaraload()
{
$laraload = $this->mock(Laraload::class);
$this->app[Kernel::class]->pushMiddleware(LaraloadMiddleware::class);
$laraload->shouldReceive('generate');
$this->app->make('config')->set('laraload.condition', CountRequests::class);
Route::get('/test', function () {
return 'ok';
});
$this->get('/test')->assertSee('ok');
}
public function testLaraloadGeneratesScript()
{
$event = Event::fake();
$this->app[Kernel::class]->pushMiddleware(LaraloadMiddleware::class);
$preload = $this->mock(Preloader::class);
$preload->shouldReceive('ignoreNotFound')
->with(true)
->andReturnSelf();
$preload->shouldReceive('memoryLimit')
->with(32)
->andReturnSelf();
$preload->shouldReceive('exclude')
->with([])
->andReturnSelf();
$preload->shouldReceive('append')
->with([])
->andReturnSelf();
$preload->shouldReceive('writeTo')
->with(config('laraload.output'))
->andReturnTrue();
$this->app->when(CountRequests::class)
->needs('$hits')
->give(1);
$this->app->make('config')->set('laraload.condition', CountRequests::class);
Route::get('/test', function () {
return 'ok';
});
$this->get('/test')->assertSee('ok');
$event->assertDispatched(PreloadCalledEvent::class, function ($event) {
return $event->success;
});
}
public function testUsesRequireInsteadOfCompile()
{
$this->app->when(CountRequests::class)
->needs('$hits')
->give(1);
$this->app->make('config')->set('laraload.use_require', true);
$this->app->make('config')->set('laraload.condition', CountRequests::class);
$preloader = $this->mock(Preloader::class);
$preloader->shouldReceive('ignoreNotFound')->andReturnSelf();
$preloader->shouldReceive('memoryLimit')->andReturnSelf();
$preloader->shouldReceive('exclude')->andReturnSelf();
$preloader->shouldReceive('append')->andReturnSelf();
$preloader->shouldReceive('useRequire')->with(config('laraload.autoload'))->andReturnSelf();
$preloader->shouldReceive('writeTo')->with(config('laraload.output'))->andReturnTrue();
$this->app[Kernel::class]->pushMiddleware(LaraloadMiddleware::class);
Route::get('/test', fn() => response('ok'));
$this->get('/test')->assertStatus(200);
}
public function testReceivesAppendedAndExcludedFiles()
{
$this->app->when(CountRequests::class)
->needs('$hits')
->give(1);
$this->app->make('config')->set('laraload.condition', CountRequests::class);
$preloader = $this->mock(Preloader::class);
$preloader->shouldReceive('ignoreNotFound')->andReturnSelf();
$preloader->shouldReceive('memoryLimit')->andReturnSelf();
$preloader->shouldReceive('exclude')->with('foo')->andReturnSelf();
$preloader->shouldReceive('append')->with('bar')->andReturnSelf();
$preloader->shouldReceive('writeTo')->with(config('laraload.output'))->andReturnTrue();
LaraloadFacade::exclude('foo');
LaraloadFacade::append('bar');
$this->app[Kernel::class]->pushMiddleware(LaraloadMiddleware::class);
Route::get('/test', fn() => response('ok'));
$this->get('/test')->assertStatus(200);
}
public function testWorksOnNonErrorCodes()
{
$laraload = $this->mock(Laraload::class);
$this->app->when(CountRequests::class)
->needs('$hits')
->give(1);
$laraload->shouldReceive('generate')->times(3);
$this->app->make('config')->set('laraload.condition', CountRequests::class);
$this->app[Kernel::class]->pushMiddleware(LaraloadMiddleware::class);
$i = rand(100, 199);
Route::get('/100', fn() => response('ok', $i));
$this->get('/100')->assertStatus($i);
$i = rand(200, 299);
Route::get('/200', fn() => response('ok', $i));
$this->get('/200')->assertStatus($i);
$i = rand(300, 399);
Route::get('/300', fn() => response('ok', $i));
$this->get('/300')->assertStatus($i);
$i = rand(400, 499);
Route::get('/400', fn() => response('ok', $i));
$this->get('/400')->assertStatus($i);
$i = rand(500, 599);
Route::get('/500', fn() => response('ok', $i));
$this->get('/500')->assertStatus($i);
}
public function testReceivesFalseForIgnoringNotFoundFiles()
{
$this->app->when(CountRequests::class)
->needs('$hits')
->give(1);
$this->app->make('config')->set('laraload.condition', CountRequests::class);
$this->app->make('config')->set('laraload.ignore-not-found', false);
$preloader = $this->mock(Preloader::class);
$preloader->shouldReceive('ignoreNotFound')->with(false)->andReturnSelf();
$preloader->shouldReceive('memoryLimit')->andReturnSelf();
$preloader->shouldReceive('exclude')->with(null)->andReturnSelf();
$preloader->shouldReceive('append')->with(null)->andReturnSelf();
$preloader->shouldReceive('writeTo')->with(config('laraload.output'))->andReturnTrue();
$this->app[Kernel::class]->pushMiddleware(LaraloadMiddleware::class);
Route::get('/test', fn() => response('ok'));
$this->get('/test')->assertStatus(200);
}
protected function tearDown() : void
{
parent::tearDown();
ConditionCallable::$called = false;
}
}
================================================
FILE: tests/Stubs/ConditionCallable.php
================================================
<?php
namespace Tests\Stubs;
class ConditionCallable
{
public static bool $called = false;
public function handle()
{
static::$called = true;
return true;
}
}
gitextract_4flgjxfq/
├── .editorconfig
├── .gitattributes
├── .github/
│ ├── FUNDING.yml
│ ├── dependabot.yml
│ └── workflows/
│ └── php.yml
├── .gitignore
├── .styleci.yml
├── LICENSE
├── README.md
├── composer.json
├── config/
│ └── laraload.php
├── phpunit.xml.dist
├── src/
│ ├── Conditions/
│ │ └── CountRequests.php
│ ├── Events/
│ │ └── PreloadCalledEvent.php
│ ├── Facades/
│ │ └── Laraload.php
│ ├── Http/
│ │ └── Middleware/
│ │ └── LaraloadMiddleware.php
│ ├── Laraload.php
│ └── LaraloadServiceProvider.php
└── tests/
├── Conditions/
│ └── CountRequestTest.php
├── PackageTest.php
└── Stubs/
└── ConditionCallable.php
SYMBOL INDEX (46 symbols across 9 files)
FILE: src/Conditions/CountRequests.php
class CountRequests (line 7) | class CountRequests
method __construct (line 35) | public function __construct(Cache $cache, int $hits = 500, string $cac...
method __invoke (line 47) | public function __invoke(): bool
FILE: src/Events/PreloadCalledEvent.php
class PreloadCalledEvent (line 5) | class PreloadCalledEvent
method __construct (line 19) | public function __construct(bool $success)
FILE: src/Facades/Laraload.php
class Laraload (line 12) | class Laraload extends Facade
method getFacadeAccessor (line 17) | protected static function getFacadeAccessor()
FILE: src/Http/Middleware/LaraloadMiddleware.php
class LaraloadMiddleware (line 10) | class LaraloadMiddleware
method __construct (line 29) | public function __construct(Config $config)
method handle (line 43) | public function handle($request, Closure $next)
method terminate (line 57) | public function terminate($request, $response)
method responseNotError (line 71) | protected function responseNotError($response): bool
method conditionIsTrue (line 81) | protected function conditionIsTrue(): bool
FILE: src/Laraload.php
class Laraload (line 9) | class Laraload
method __construct (line 53) | public function __construct(Config $config, Dispatcher $dispatcher, Pr...
method append (line 67) | public function append($append): void
method exclude (line 79) | public function exclude($exclude): void
method generate (line 89) | public function generate(): bool
FILE: src/LaraloadServiceProvider.php
class LaraloadServiceProvider (line 11) | class LaraloadServiceProvider extends ServiceProvider
method register (line 18) | public function register()
method boot (line 34) | public function boot(Repository $config, Kernel $kernel)
method shouldRun (line 55) | protected function shouldRun(Repository $config): bool
FILE: tests/Conditions/CountRequestTest.php
class CountRequestTest (line 20) | class CountRequestTest extends TestCase
method getPackageProviders (line 22) | protected function getPackageProviders($app)
method getPackageAliases (line 27) | protected function getPackageAliases($app)
method testReaches500AndResets (line 34) | public function testReaches500AndResets()
method testUsesNonDefaultConfig (line 47) | public function testUsesNonDefaultConfig()
FILE: tests/PackageTest.php
class PackageTest (line 19) | class PackageTest extends TestCase
method getPackageProviders (line 21) | protected function getPackageProviders($app)
method getPackageAliases (line 26) | protected function getPackageAliases($app)
method testPublishesConfig (line 33) | public function testPublishesConfig()
method testDoesntRegisterTerminableMiddlewareInTesting (line 46) | public function testDoesntRegisterTerminableMiddlewareInTesting()
method testDoesntWorkWithErrorResponse (line 53) | public function testDoesntWorkWithErrorResponse()
method testReachesCallable (line 70) | public function testReachesCallable()
method testCallableWithMethod (line 89) | public function testCallableWithMethod()
method testCallableWithMethodAndParameters (line 109) | public function testCallableWithMethodAndParameters()
method testConditionWorks (line 130) | public function testConditionWorks()
method testConditionsCallsLaraload (line 153) | public function testConditionsCallsLaraload()
method testLaraloadGeneratesScript (line 170) | public function testLaraloadGeneratesScript()
method testUsesRequireInsteadOfCompile (line 211) | public function testUsesRequireInsteadOfCompile()
method testReceivesAppendedAndExcludedFiles (line 235) | public function testReceivesAppendedAndExcludedFiles()
method testWorksOnNonErrorCodes (line 260) | public function testWorksOnNonErrorCodes()
method testReceivesFalseForIgnoringNotFoundFiles (line 293) | public function testReceivesFalseForIgnoringNotFoundFiles()
method tearDown (line 316) | protected function tearDown() : void
FILE: tests/Stubs/ConditionCallable.php
class ConditionCallable (line 5) | class ConditionCallable
method handle (line 9) | public function handle()
Condensed preview — 21 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (44K chars).
[
{
"path": ".editorconfig",
"chars": 312,
"preview": "; This file is for unifying the coding style for different editors and IDEs.\n; More information at http://editorconfig.o"
},
{
"path": ".gitattributes",
"chars": 429,
"preview": "# Path-based git attributes\n# https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html\n\n# Ignore all test and"
},
{
"path": ".github/FUNDING.yml",
"chars": 101,
"preview": "# Help me support this package\n\nko_fi: DarkGhostHunter\ncustom: ['https://paypal.me/darkghosthunter']\n"
},
{
"path": ".github/dependabot.yml",
"chars": 148,
"preview": "version: 2\nupdates:\n- package-ecosystem: composer\n directory: \"/\"\n schedule:\n interval: daily\n time: \"09:00\"\n o"
},
{
"path": ".github/workflows/php.yml",
"chars": 1743,
"preview": "name: PHP Composer\n\non:\n push:\n pull_request:\n\njobs:\n test:\n\n runs-on: ubuntu-latest\n strategy:\n fail-fast"
},
{
"path": ".gitignore",
"chars": 46,
"preview": "build\ncomposer.lock\ndocs\nvendor\ncoverage\n.idea"
},
{
"path": ".styleci.yml",
"chars": 66,
"preview": "preset: laravel\n\ndisabled:\n - single_class_element_per_statement\n"
},
{
"path": "LICENSE",
"chars": 1077,
"preview": "MIT License\n\nCopyright (c) Italo Israel Baeza Cabrera\n\nPermission is hereby granted, free of charge, to any person obtai"
},
{
"path": "README.md",
"chars": 11122,
"preview": "## This package has been superseeded by [Laragear/Preload](https://github.com/Laragear/Preload).\n\nPlease migrate to the "
},
{
"path": "composer.json",
"chars": 1666,
"preview": "{\n \"name\": \"darkghosthunter/laraload\",\n \"description\": \"Effortlessly make a Preload script for your Laravel applic"
},
{
"path": "config/laraload.php",
"chars": 2977,
"preview": "<?php\n\nreturn [\n\n /*\n |--------------------------------------------------------------------------\n | Main Switc"
},
{
"path": "phpunit.xml.dist",
"chars": 1145,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit bootstrap=\"vendor/autoload.php\"\n backupGlobals=\"false\"\n "
},
{
"path": "src/Conditions/CountRequests.php",
"chars": 1317,
"preview": "<?php\n\nnamespace DarkGhostHunter\\Laraload\\Conditions;\n\nuse Illuminate\\Contracts\\Cache\\Repository as Cache;\n\nclass CountR"
},
{
"path": "src/Events/PreloadCalledEvent.php",
"chars": 392,
"preview": "<?php\n\nnamespace DarkGhostHunter\\Laraload\\Events;\n\nclass PreloadCalledEvent\n{\n /**\n * Generation status\n *\n "
},
{
"path": "src/Facades/Laraload.php",
"chars": 456,
"preview": "<?php\n\nnamespace DarkGhostHunter\\Laraload\\Facades;\n\nuse Illuminate\\Support\\Facades\\Facade;\n\n/**\n * @method static void a"
},
{
"path": "src/Http/Middleware/LaraloadMiddleware.php",
"chars": 2132,
"preview": "<?php\n\nnamespace DarkGhostHunter\\Laraload\\Http\\Middleware;\n\nuse Closure;\nuse DarkGhostHunter\\Laraload\\Laraload;\nuse Illu"
},
{
"path": "src/Laraload.php",
"chars": 2440,
"preview": "<?php\n\nnamespace DarkGhostHunter\\Laraload;\n\nuse DarkGhostHunter\\Preloader\\Preloader;\nuse Illuminate\\Contracts\\Events\\Dis"
},
{
"path": "src/LaraloadServiceProvider.php",
"chars": 1708,
"preview": "<?php\n\nnamespace DarkGhostHunter\\Laraload;\n\nuse Illuminate\\Config\\Repository;\nuse Illuminate\\Contracts\\Http\\Kernel;\nuse "
},
{
"path": "tests/Conditions/CountRequestTest.php",
"chars": 1634,
"preview": "<?php\n\nnamespace Tests\\Conditions;\n\nuse Exception;\nuse Illuminate\\Contracts\\Cache\\Repository;\nuse Orchestra\\Testbench\\Te"
},
{
"path": "tests/PackageTest.php",
"chars": 10046,
"preview": "<?php\n\nnamespace Tests;\n\nuse Exception;\nuse Orchestra\\Testbench\\TestCase;\nuse Tests\\Stubs\\ConditionCallable;\nuse Illumin"
},
{
"path": "tests/Stubs/ConditionCallable.php",
"chars": 195,
"preview": "<?php\n\nnamespace Tests\\Stubs;\n\nclass ConditionCallable\n{\n public static bool $called = false;\n\n public function ha"
}
]
About this extraction
This page contains the full source code of the DarkGhostHunter/Laraload GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 21 files (40.2 KB), approximately 10.2k tokens, and a symbol index with 46 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.