diff --git a/.github/workflows/analyse.yml b/.github/workflows/analyse.yml
new file mode 100644
index 0000000..885b94d
--- /dev/null
+++ b/.github/workflows/analyse.yml
@@ -0,0 +1,37 @@
+name: analyse
+
+on: ['push', 'pull_request']
+
+jobs:
+ test:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: true
+ matrix:
+ os: [ubuntu-latest]
+ php: [8.3]
+ laravel: [11.*]
+ stability: [prefer-stable]
+ include:
+ - laravel: 11.*
+ testbench: 9.*
+
+ name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }}
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php }}
+ extensions: dom, curl, libxml, mbstring, zip, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo
+ coverage: none
+
+ - name: Install dependencies
+ run: |
+ composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update
+ composer update --${{ matrix.stability }} --prefer-dist --no-interaction
+ - name: Analyse
+ run: composer analyse
\ No newline at end of file
diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml
new file mode 100644
index 0000000..161eadb
--- /dev/null
+++ b/.github/workflows/changelog.yml
@@ -0,0 +1,29 @@
+name: "Update Changelog"
+
+on:
+ release:
+ types: [ published, edited, deleted ]
+
+jobs:
+ generate:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v3
+ with:
+ ref: ${{ github.event.release.target_commitish }}
+
+ - name: Generate changelog
+ uses: justbetter/generate-changelogs-action@main
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ repository: ${{ github.repository }}
+
+ - name: Commit CHANGELOG
+ uses: stefanzweifel/git-auto-commit-action@v4
+ with:
+ branch: ${{ github.event.release.target_commitish }}
+ commit_message: Update CHANGELOG
+ file_pattern: CHANGELOG.md
\ No newline at end of file
diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml
new file mode 100644
index 0000000..18d1fa0
--- /dev/null
+++ b/.github/workflows/coverage.yml
@@ -0,0 +1,38 @@
+name: coverage
+
+on: ['push', 'pull_request']
+
+jobs:
+ test:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: true
+ matrix:
+ os: [ubuntu-latest]
+ php: [8.3]
+ laravel: [11.*]
+ stability: [prefer-stable]
+ include:
+ - laravel: 11.*
+ testbench: 9.*
+
+ name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }}
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php }}
+ extensions: dom, curl, libxml, mbstring, zip, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo, xdebug
+ coverage: xdebug
+
+ - name: Install dependencies
+ run: |
+ composer config allow-plugins.pestphp/pest-plugin true
+ composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update
+ composer update --${{ matrix.stability }} --prefer-dist --no-interaction
+ - name: Execute tests
+ run: XDEBUG_MODE=coverage php vendor/bin/pest --coverage --min=100
\ No newline at end of file
diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml
new file mode 100644
index 0000000..a61cfdc
--- /dev/null
+++ b/.github/workflows/style.yml
@@ -0,0 +1,32 @@
+name: style
+
+on:
+ push:
+ branches:
+ - master
+jobs:
+ style:
+ name: Style
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: 8.3
+ extensions: dom, curl, libxml, mbstring, zip, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo
+ coverage: none
+
+ - name: Install dependencies
+ run: composer install
+
+ - name: Style
+ run: composer fix-style
+
+ - name: Commit Changes
+ uses: stefanzweifel/git-auto-commit-action@v4
+ with:
+ commit_message: Fix styling changes
\ No newline at end of file
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
new file mode 100644
index 0000000..bac831d
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,40 @@
+name: tests
+
+on: [ 'push', 'pull_request' ]
+
+jobs:
+ test:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: true
+ matrix:
+ os: [ ubuntu-latest ]
+ php: [ 8.2, 8.3 ]
+ laravel: [ 11.* ]
+ stability: [ prefer-lowest, prefer-stable ]
+ include:
+ - laravel: 11.*
+ testbench: 9.*
+ exclude:
+ - laravel: 11.*
+ php: 8.1
+
+ name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }}
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php }}
+ extensions: dom, curl, libxml, mbstring, zip, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo
+ coverage: none
+
+ - name: Install dependencies
+ run: |
+ composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update
+ composer update --${{ matrix.stability }} --prefer-dist --no-interaction
+ - name: Execute tests
+ run: composer test
\ No newline at end of file
diff --git a/composer.json b/composer.json
index bfa5c76..e1c0175 100644
--- a/composer.json
+++ b/composer.json
@@ -15,16 +15,19 @@
}
],
"require": {
- "php": "^8.0",
+ "php": "^8.1|^8.2|^8.3",
"ext-fileinfo": "*",
- "statamic/cms": "^4.0 || ^5.0",
- "laravel/framework": "^9.50.0 || ^10.0 || ^11.0",
+ "statamic/cms": "^5.0",
+ "laravel/framework": "^10.0 || ^11.0",
"league/glide": "^2.2"
},
"require-dev": {
- "laravel/pint": "^1.1",
- "orchestra/testbench": "^7.0 || ^8.0",
- "phpunit/phpunit": "^9.0 || ^10.0"
+ "laravel/pint": "^1.7",
+ "larastan/larastan": "^2.5",
+ "phpstan/phpstan-mockery": "^1.1",
+ "phpunit/phpunit": "^10.1",
+ "orchestra/testbench": "^8.0|^9.0",
+ "pestphp/pest": "^2.0"
},
"autoload": {
"psr-4": {
@@ -38,12 +41,20 @@
},
"scripts": {
"test": "phpunit",
- "style": "pint --test"
+ "analyse": "phpstan",
+ "style": "pint --test",
+ "quality": [
+ "@test",
+ "@analyse",
+ "@style"
+ ],
+ "fix-style": "pint"
},
"config": {
"sort-packages": true,
"allow-plugins": {
- "pixelfear/composer-dist-plugin": true
+ "pixelfear/composer-dist-plugin": true,
+ "pestphp/pest-plugin": true
}
},
"extra": {
diff --git a/config/image-optimize.php b/config/image-optimize.php
index 079767d..b274569 100644
--- a/config/image-optimize.php
+++ b/config/image-optimize.php
@@ -18,4 +18,4 @@
// You can exclude containers from optimization entirely here
'excluded_containers' => [],
-];
\ No newline at end of file
+];
diff --git a/phpstan.neon b/phpstan.neon
new file mode 100644
index 0000000..ffdbf4b
--- /dev/null
+++ b/phpstan.neon
@@ -0,0 +1,11 @@
+includes:
+ - ./vendor/larastan/larastan/extension.neon
+ - ./vendor/phpstan/phpstan-mockery/extension.neon
+
+parameters:
+ paths:
+ - src
+ - tests
+ level: 8
+ ignoreErrors:
+ - identifier: missingType.iterableValue
diff --git a/phpunit.xml b/phpunit.xml
index 6dcf683..91b8cae 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -1,17 +1,14 @@
-
+
./tests/*
-
+
+
-
+
+
\ No newline at end of file
diff --git a/routes/cp.php b/routes/cp.php
index 81fc3f4..a96dee0 100644
--- a/routes/cp.php
+++ b/routes/cp.php
@@ -6,7 +6,7 @@
Route::prefix('statamic-image-optimize')
->name('statamic-image-optimize.')
->controller(ImageResizeController::class)
- ->group(function() {
+ ->group(function () {
Route::get('/', 'index')->name('index');
Route::get('/resize-images/{forceAll?}', 'resizeImages')->name('resize-images');
Route::get('/resize-images-count/{batchId?}', 'resizeImagesJobCount')->name('resize-images-count');
diff --git a/src/Actions/OptimizeAssets.php b/src/Actions/OptimizeAssets.php
index c82d97c..a96eca9 100644
--- a/src/Actions/OptimizeAssets.php
+++ b/src/Actions/OptimizeAssets.php
@@ -4,32 +4,35 @@
use JustBetter\ImageOptimize\Jobs\ResizeImageJob;
use Statamic\Actions\Action;
-use Statamic\Contracts\Assets\Asset;
+use Statamic\Assets\Asset;
class OptimizeAssets extends Action
{
- public static function title()
+ public static function title(): string
{
return __('image-optimize::messages.optimize');
}
- public function visibleTo($item)
+ // @phpstan-ignore-next-line
+ public function visibleTo($item): bool
{
return $item instanceof Asset;
}
- public function visibleToBulk($items)
+ // @phpstan-ignore-next-line
+ public function visibleToBulk($items): bool
{
return $this->visibleTo($items->first());
}
- public function run($assets, $values)
+ // @phpstan-ignore-next-line
+ public function run($assets, $values): void
{
- collect($assets)
- ->each(function ($asset) {
- if ($asset instanceof Asset && $asset->isImage()) {
- ResizeImageJob::dispatch($asset);
- }
+ // @phpstan-ignore-next-line
+ collect($assets ?? [])
+ ->filter(fn (mixed $asset): bool => $asset instanceof Asset)
+ ->each(function (Asset $asset): void {
+ ResizeImageJob::dispatch($asset);
});
}
}
diff --git a/src/Actions/ResizeImage.php b/src/Actions/ResizeImage.php
index e8e4cc8..d9ff519 100644
--- a/src/Actions/ResizeImage.php
+++ b/src/Actions/ResizeImage.php
@@ -13,6 +13,13 @@ class ResizeImage implements ResizesImage
{
public function resize(Asset $asset, ?int $width = null, ?int $height = null): void
{
+ if (! $asset->exists() ||
+ ! $asset->isImage() ||
+ in_array($asset->containerHandle(), config('image-optimize.excluded_containers'))
+ ) {
+ return;
+ }
+
$width ??= (int) config('image-optimize.default_resize_width');
$height ??= (int) config('image-optimize.default_resize_height');
@@ -20,7 +27,7 @@ public function resize(Asset $asset, ?int $width = null, ?int $height = null): v
try {
$orientedImage = Image::make($asset->resolvedPath())->orientate();
- $image = (new Size())->runMaxResize($orientedImage, $width, $height);
+ $image = (new Size)->runMaxResize($orientedImage, $width, $height);
$asset->disk()->filesystem()->put($asset->path(), $image->encode());
@@ -37,6 +44,6 @@ public function resize(Asset $asset, ?int $width = null, ?int $height = null): v
public static function bind(): void
{
- app()->singleton(ResizesImage::class,static::class);
+ app()->singleton(ResizesImage::class, static::class);
}
}
diff --git a/src/Actions/ResizeImages.php b/src/Actions/ResizeImages.php
index 28391e0..d689655 100644
--- a/src/Actions/ResizeImages.php
+++ b/src/Actions/ResizeImages.php
@@ -2,34 +2,34 @@
namespace JustBetter\ImageOptimize\Actions;
+use Illuminate\Bus\Batch;
+use Illuminate\Support\Facades\Bus;
use JustBetter\ImageOptimize\Contracts\ResizesImages;
use JustBetter\ImageOptimize\Events\ImagesResizedEvent;
use JustBetter\ImageOptimize\Jobs\ResizeImageJob;
use Statamic\Assets\Asset;
-use Illuminate\Bus\Batch;
-use Illuminate\Support\Facades\Bus;
use Statamic\Assets\AssetCollection;
+use Statamic\Facades\Asset as AssetFacade;
class ResizeImages implements ResizesImages
{
public function resize(bool $forceAll = false): Batch
{
/** @var AssetCollection $assets */
- $assets = Asset::all();
+ $assets = AssetFacade::all();
- $assets
- ->getOptimizableAssets()
- ->when(!$forceAll, fn() => $assets->whereNull('image-optimized'));
+ $assets->getOptimizableAssets() // @phpstan-ignore-line
+ ->when(! $forceAll, fn () => $assets->whereNull('image-optimized'));
$jobs = $assets
- ->filter(fn(Asset $asset): bool => $asset->isImage())
+ ->filter(fn (Asset $asset): bool => $asset->isImage())
->map(fn (Asset $asset) => new ResizeImageJob($asset->hydrate()));
return Bus::batch($jobs)
->name('image-optimize')
->onConnection(config('image-optimize.default_queue_connection'))
->onQueue(config('image-optimize.default_queue_name'))
- ->then(function(): void {
+ ->then(function (): void {
ImagesResizedEvent::dispatch();
})
->dispatch();
@@ -37,6 +37,6 @@ public function resize(bool $forceAll = false): Batch
public static function bind(): void
{
- app()->singleton(ResizesImages::class,static::class);
+ app()->singleton(ResizesImages::class, static::class);
}
}
diff --git a/src/Commands/ResizeImagesCommand.php b/src/Commands/ResizeImagesCommand.php
index 53705b2..2145564 100644
--- a/src/Commands/ResizeImagesCommand.php
+++ b/src/Commands/ResizeImagesCommand.php
@@ -3,10 +3,11 @@
namespace JustBetter\ImageOptimize\Commands;
use Illuminate\Console\Command;
+use Illuminate\Support\Facades\DB;
use JustBetter\ImageOptimize\Contracts\ResizesImages;
use JustBetter\ImageOptimize\Jobs\ResizeImagesJob;
-use Illuminate\Support\Facades\DB;
+/** @codeCoverageIgnore */
class ResizeImagesCommand extends Command
{
protected $signature = 'justbetter:optimize:images {--forceAll}';
@@ -22,14 +23,15 @@ public function handle(ResizesImages $resizesImages): int
DB::connection()->getPdo();
} catch (\Exception $e) {
$this->error('You need an active database connection in order to use the optimize addon.');
- return false;
+
+ return static::FAILURE;
}
if ($this->getOutput()->isVerbose()) {
- $this->line("Starting the resize images job");
+ $this->line('Starting the resize images job');
if ($forceAll) {
- $this->comment("Forcing to optimize all images");
+ $this->comment('Forcing to optimize all images');
}
$batch = $resizesImages->resize($forceAll);
@@ -37,7 +39,7 @@ public function handle(ResizesImages $resizesImages): int
$progress = $this->output->createProgressBar($batch->totalJobs);
$progress->start();
- while($batch->pendingJobs && !$batch->finished() && !$batch->cancelled()) {
+ while ($batch->pendingJobs && ! $batch->finished() && ! $batch->cancelled()) {
$batch = $batch->fresh();
$progress->setProgress($batch->processedJobs());
}
@@ -45,10 +47,10 @@ public function handle(ResizesImages $resizesImages): int
$progress->finish();
$this->output->newLine(2);
- $this->info("All images have been resized");
+ $this->info('All images have been resized');
} else {
ResizeImagesJob::dispatch($forceAll);
- $this->info("Jobs dispatched");
+ $this->info('Jobs dispatched');
}
return static::SUCCESS;
diff --git a/src/Contracts/ResizesImage.php b/src/Contracts/ResizesImage.php
index 345f903..0aabc2d 100644
--- a/src/Contracts/ResizesImage.php
+++ b/src/Contracts/ResizesImage.php
@@ -7,4 +7,4 @@
interface ResizesImage
{
public function resize(Asset $asset, ?int $width = null, ?int $height = null): void;
-}
\ No newline at end of file
+}
diff --git a/src/Http/Controllers/CP/ImageResizeController.php b/src/Http/Controllers/CP/ImageResizeController.php
index 9dd34a3..2dd9914 100644
--- a/src/Http/Controllers/CP/ImageResizeController.php
+++ b/src/Http/Controllers/CP/ImageResizeController.php
@@ -2,6 +2,8 @@
namespace JustBetter\ImageOptimize\Http\Controllers\CP;
+use Illuminate\Contracts\View\Factory;
+use Illuminate\Contracts\View\View;
use Illuminate\Http\JsonResponse;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Bus;
@@ -11,9 +13,12 @@
class ImageResizeController extends Controller
{
- public function index() : string
+ /**
+ * @codeCoverageIgnore
+ */
+ public function index(): Factory|View|string
{
- $assets = Asset::all()->getOptimizableAssets();
+ $assets = Asset::all()->getOptimizableAssets(); // @phpstan-ignore-line
$unoptimizedAssets = $assets->whereNull('image-optimized');
$databaseConnected = true;
@@ -31,30 +36,29 @@ public function index() : string
]);
}
- public function resizeImages(ResizesImages $resizesImages, string $forceAll = null): JsonResponse
+ public function resizeImages(ResizesImages $resizesImages, ?string $forceAll = null): JsonResponse
{
$batch = $resizesImages->resize($forceAll !== null);
return response()->json([
'imagesOptimized' => true,
- 'batchId' => $batch->id
+ 'batchId' => $batch->id,
]);
}
- public function resizeImagesJobCount(string $batchId = null): JsonResponse
+ public function resizeImagesJobCount(?string $batchId = null): JsonResponse
{
$batch = $batchId ? Bus::findBatch($batchId) : null;
if ($batch) {
return response()->json([
- 'assetsToOptimize' => $batch->pendingJobs ?? 0,
- 'assetTotal' => $batch->totalJobs ?? 0
+ 'assetsToOptimize' => $batch->pendingJobs,
+ 'assetTotal' => $batch->totalJobs,
]);
}
$allAssets = Asset::all();
- $assets = $allAssets
- ->getOptimizableAssets()
+ $assets = $allAssets->getOptimizableAssets() // @phpstan-ignore-line
->whereNull('image-optimized');
return response()->json([
diff --git a/src/Jobs/ResizeImageJob.php b/src/Jobs/ResizeImageJob.php
index 3d82917..3fedfe8 100644
--- a/src/Jobs/ResizeImageJob.php
+++ b/src/Jobs/ResizeImageJob.php
@@ -2,6 +2,7 @@
namespace JustBetter\ImageOptimize\Jobs;
+use Illuminate\Bus\Batchable;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
@@ -9,14 +10,13 @@
use Illuminate\Queue\InteractsWithQueue;
use JustBetter\ImageOptimize\Contracts\ResizesImage;
use Statamic\Assets\Asset;
-use Illuminate\Bus\Batchable;
-class ResizeImageJob implements ShouldQueue, ShouldBeUnique
+class ResizeImageJob implements ShouldBeUnique, ShouldQueue
{
+ use Batchable;
use Dispatchable;
use InteractsWithQueue;
use Queueable;
- use Batchable;
public function __construct(
public Asset $asset,
diff --git a/src/Jobs/ResizeImagesJob.php b/src/Jobs/ResizeImagesJob.php
index e9292bb..1d9b2d7 100644
--- a/src/Jobs/ResizeImagesJob.php
+++ b/src/Jobs/ResizeImagesJob.php
@@ -9,7 +9,7 @@
use Illuminate\Queue\InteractsWithQueue;
use JustBetter\ImageOptimize\Contracts\ResizesImages;
-class ResizeImagesJob implements ShouldQueue, ShouldBeUnique
+class ResizeImagesJob implements ShouldBeUnique, ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
diff --git a/src/Listeners/AssetUploadedListener.php b/src/Listeners/AssetUploadedListener.php
index 5b31db1..feec700 100644
--- a/src/Listeners/AssetUploadedListener.php
+++ b/src/Listeners/AssetUploadedListener.php
@@ -2,10 +2,10 @@
namespace JustBetter\ImageOptimize\Listeners;
+use JustBetter\ImageOptimize\Jobs\ResizeImageJob;
use Statamic\Assets\Asset;
-use Statamic\Events\AssetUploaded;
use Statamic\Events\AssetReuploaded;
-use JustBetter\ImageOptimize\Jobs\ResizeImageJob;
+use Statamic\Events\AssetUploaded;
class AssetUploadedListener
{
@@ -14,12 +14,6 @@ public function handle(AssetUploaded|AssetReuploaded $event): void
/** @var Asset $asset */
$asset = $event->asset;
- if (!$asset->exists()) {
- return;
- }
-
- if ($asset->isImage() && !in_array($asset->containerHandle(), config('image-optimize.excluded_containers'))) {
- ResizeImageJob::dispatch($asset);
- }
+ ResizeImageJob::dispatch($asset);
}
}
diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php
index bc356eb..26bf7b3 100644
--- a/src/ServiceProvider.php
+++ b/src/ServiceProvider.php
@@ -6,12 +6,13 @@
use JustBetter\ImageOptimize\Actions\ResizeImage;
use JustBetter\ImageOptimize\Actions\ResizeImages;
use JustBetter\ImageOptimize\Commands\ResizeImagesCommand;
+use JustBetter\ImageOptimize\Listeners\AssetUploadedListener;
use Statamic\Assets\AssetCollection;
+use Statamic\CP\Navigation\Nav as Navigation;
+use Statamic\Events\AssetReuploaded;
+use Statamic\Events\AssetUploaded;
use Statamic\Facades\CP\Nav;
use Statamic\Providers\AddonServiceProvider;
-use JustBetter\ImageOptimize\Listeners\AssetUploadedListener;
-use Statamic\Events\AssetUploaded;
-use Statamic\Events\AssetReuploaded;
class ServiceProvider extends AddonServiceProvider
{
@@ -20,11 +21,11 @@ class ServiceProvider extends AddonServiceProvider
];
protected $routes = [
- 'cp' => __DIR__ . '/../routes/cp.php'
+ 'cp' => __DIR__.'/../routes/cp.php',
];
protected $scripts = [
- __DIR__ . '/../dist/js/statamic-image-optimize.js'
+ __DIR__.'/../dist/js/statamic-image-optimize.js',
];
public function register(): void
@@ -34,7 +35,6 @@ public function register(): void
->registerMacros();
}
-
protected function registerConfig(): static
{
$this->mergeConfigFrom(__DIR__.'/../config/image-optimize.php', 'image-optimize');
@@ -65,7 +65,7 @@ public function boot(): void
{
parent::boot();
- $this->loadViewsFrom(__DIR__ . '/../resources/views', 'statamic-image-optimize');
+ $this->loadViewsFrom(__DIR__.'/../resources/views', 'statamic-image-optimize');
$this->bootPublishables()
->bootEvents()
@@ -74,8 +74,6 @@ public function boot(): void
->handleTranslations();
}
-
-
public function bootEvents(): static
{
Event::listen([AssetUploaded::class, AssetReuploaded::class], AssetUploadedListener::class);
@@ -86,7 +84,7 @@ public function bootEvents(): static
protected function bootCommands(): static
{
$this->commands([
- ResizeImagesCommand::class
+ ResizeImagesCommand::class,
]);
return $this;
@@ -101,9 +99,12 @@ protected function bootPublishables(): static
return $this;
}
+ /**
+ * @codeCoverageIgnore
+ */
protected function bootNav(): static
{
- Nav::extend(function ($nav) {
+ Nav::extend(function (Navigation $nav): void {
$nav->create('Image Optimize')
->section('Tools')
->route('statamic-image-optimize.index')
@@ -115,10 +116,10 @@ protected function bootNav(): static
protected function handleTranslations(): static
{
- $this->loadTranslationsFrom(__DIR__ . '/../resources/lang', 'image-optimize');
+ $this->loadTranslationsFrom(__DIR__.'/../resources/lang', 'image-optimize');
$this->publishes([
- __DIR__ . '/../resources/lang' => resource_path('lang/vendor/statamic-image-optimize'),
+ __DIR__.'/../resources/lang' => resource_path('lang/vendor/statamic-image-optimize'),
], 'image-optimize-translations');
return $this;
diff --git a/tests/Actions/OptimizeAssetsTest.php b/tests/Actions/OptimizeAssetsTest.php
new file mode 100644
index 0000000..067e7b0
--- /dev/null
+++ b/tests/Actions/OptimizeAssetsTest.php
@@ -0,0 +1,65 @@
+assertEquals('Optimize', OptimizeAssets::title());
+ }
+
+ #[Test]
+ public function it_can_be_visible(): void
+ {
+ $asset = $this->createAsset();
+
+ /** @var OptimizeAssets $action */
+ $action = app(OptimizeAssets::class);
+
+ $this->assertTrue(
+ $action->visibleTo($asset)
+ );
+ }
+
+ #[Test]
+ public function it_can_be_visible_to_bulk(): void
+ {
+ $assets = collect([
+ $this->createAsset(),
+ ]);
+
+ /** @var OptimizeAssets $action */
+ $action = app(OptimizeAssets::class);
+
+ $this->assertTrue(
+ $action->visibleToBulk($assets)
+ );
+ }
+
+ #[Test]
+ public function it_can_run(): void
+ {
+ Bus::fake();
+
+ $assets = collect([
+ $this->createAsset(),
+ 'asset',
+ false,
+ null,
+ ]);
+
+ /** @var OptimizeAssets $action */
+ $action = app(OptimizeAssets::class);
+ $action->run($assets, null);
+
+ Bus::assertDispatched(ResizeImageJob::class, 1);
+ }
+}
diff --git a/tests/Actions/ResizeImageTest.php b/tests/Actions/ResizeImageTest.php
new file mode 100644
index 0000000..7fc1270
--- /dev/null
+++ b/tests/Actions/ResizeImageTest.php
@@ -0,0 +1,68 @@
+createAsset();
+
+ /** @var ResizeImage $action */
+ $action = app(ResizeImage::class);
+ $action->resize($asset, 100, 100);
+
+ $this->assertEquals(100, $asset->meta('width'));
+ $this->assertEquals(63, $asset->meta('height'));
+ $this->assertEquals(1, $asset->meta('data.image-optimized'));
+
+ Event::assertDispatched(ImageResizedEvent::class);
+ }
+
+ #[Test]
+ public function it_can_ignore_excluded_containers(): void
+ {
+ Event::fake();
+
+ config()->set('image-optimize.excluded_containers', [
+ 'test_container',
+ ]);
+
+ $asset = $this->createAsset();
+
+ /** @var ResizeImage $action */
+ $action = app(ResizeImage::class);
+ $action->resize($asset);
+
+ Event::assertNotDispatched(ImageResizedEvent::class);
+ }
+
+ #[Test]
+ public function it_can_catch_exceptions(): void
+ {
+ Event::fake();
+
+ Image::spy()
+ ->shouldReceive('make')
+ ->andThrow(NotReadableException::class);
+
+ $asset = $this->createAsset();
+
+ /** @var ResizeImage $action */
+ $action = app(ResizeImage::class);
+ $action->resize($asset);
+
+ Event::assertNotDispatched(ImageResizedEvent::class);
+ }
+}
diff --git a/tests/Actions/ResizeImagesTest.php b/tests/Actions/ResizeImagesTest.php
new file mode 100644
index 0000000..c1318b8
--- /dev/null
+++ b/tests/Actions/ResizeImagesTest.php
@@ -0,0 +1,50 @@
+createAsset();
+
+ /** @var ResizeImages $action */
+ $action = app(ResizeImages::class);
+ $action->resize();
+
+ Bus::assertBatched(fn (PendingBatchFake $batch): bool => $batch->jobs->count() === 1);
+ }
+
+ #[Test]
+ #[WithMigration('queue')]
+ public function it_can_dispatch_events(): void
+ {
+ Bus::fake();
+ Event::fake();
+
+ /** @var ResizeImages $action */
+ $action = app(ResizeImages::class);
+
+ $batch = $action->resize();
+
+ /** @var non-empty-array $thenCallbacks */
+ $thenCallbacks = $batch->then; // @phpstan-ignore-line
+
+ call_user_func($thenCallbacks[0], $batch);
+
+ Event::assertDispatched(ImagesResizedEvent::class);
+ }
+}
diff --git a/tests/Http/Controllers/ImageResizeControllerTest.php b/tests/Http/Controllers/ImageResizeControllerTest.php
new file mode 100644
index 0000000..26bf788
--- /dev/null
+++ b/tests/Http/Controllers/ImageResizeControllerTest.php
@@ -0,0 +1,73 @@
+toImmutable());
+
+ $this->mock(ResizesImages::class, function (MockInterface $mock) use ($fakeBatch): void {
+ $mock
+ ->shouldReceive('resize')
+ ->andReturn($fakeBatch);
+ });
+
+ $this
+ ->withoutMiddleware()
+ ->get(route('statamic.cp.statamic-image-optimize.resize-images'))
+ ->assertSuccessful()
+ ->assertJson([
+ 'imagesOptimized' => true,
+ 'batchId' => '::batch-id::',
+ ]);
+ }
+
+ #[Test]
+ public function it_can_get_resize_images_count(): void
+ {
+ Bus::fake();
+
+ $this->createAsset();
+
+ $this
+ ->withoutMiddleware()
+ ->get(route('statamic.cp.statamic-image-optimize.resize-images-count'))
+ ->assertSuccessful()
+ ->assertJson([
+ 'assetsToOptimize' => 1,
+ 'assetTotal' => 1,
+ ]);
+ }
+
+ #[Test]
+ public function it_can_get_resize_images_count_with_batch(): void
+ {
+ Bus::fake();
+
+ $this->createAsset();
+ $fakeBatch = new BatchFake('::batch-id::', '::name::', 1, 0, 0, [], [], now()->toImmutable());
+
+ Bus::spy()
+ ->shouldReceive('findBatch')
+ ->andReturn($fakeBatch);
+
+ $this
+ ->withoutMiddleware()
+ ->get(route('statamic.cp.statamic-image-optimize.resize-images-count', ['batchId' => '::batch-id::']))
+ ->assertSuccessful()
+ ->assertJson([
+ 'assetsToOptimize' => 0,
+ 'assetTotal' => 1,
+ ]);
+ }
+}
diff --git a/tests/Jobs/ResizeImageJobTest.php b/tests/Jobs/ResizeImageJobTest.php
new file mode 100644
index 0000000..5cbce9f
--- /dev/null
+++ b/tests/Jobs/ResizeImageJobTest.php
@@ -0,0 +1,26 @@
+createAsset();
+
+ $this->mock(ResizesImage::class, function (MockInterface $mock): void {
+ $mock
+ ->shouldReceive('resize')
+ ->once();
+ });
+
+ ResizeImageJob::dispatch($asset, 100, 100);
+ }
+}
diff --git a/tests/Jobs/ResizeImagesJobTest.php b/tests/Jobs/ResizeImagesJobTest.php
new file mode 100644
index 0000000..1e68613
--- /dev/null
+++ b/tests/Jobs/ResizeImagesJobTest.php
@@ -0,0 +1,39 @@
+mock(ResizesImages::class, function (MockInterface $mock) use ($forceAll): void {
+ $mock
+ ->shouldReceive('resize')
+ ->with($forceAll)
+ ->once();
+ });
+
+ ResizeImagesJob::dispatch($forceAll);
+ }
+
+ public static function cases(): array
+ {
+ return [
+ 'true' => [
+ 'forceAll' => true,
+ ],
+ 'false' => [
+ 'forceAll' => false,
+ ],
+ ];
+ }
+}
diff --git a/tests/Listeners/AssetUploadedListenerTest.php b/tests/Listeners/AssetUploadedListenerTest.php
new file mode 100644
index 0000000..54c121f
--- /dev/null
+++ b/tests/Listeners/AssetUploadedListenerTest.php
@@ -0,0 +1,29 @@
+createAsset();
+
+ $event = new AssetUploaded($asset);
+
+ /** @var AssetUploadedListener $listener */
+ $listener = app(AssetUploadedListener::class);
+ $listener->handle($event);
+
+ Bus::assertDispatched(ResizeImageJob::class);
+ }
+}
diff --git a/tests/TestCase.php b/tests/TestCase.php
index d424235..9b90ef9 100644
--- a/tests/TestCase.php
+++ b/tests/TestCase.php
@@ -2,15 +2,85 @@
namespace JustBetter\ImageOptimize\Tests;
+use Illuminate\Foundation\Testing\Concerns\InteractsWithViews;
+use Illuminate\Foundation\Testing\LazilyRefreshDatabase;
+use Illuminate\Support\Facades\Storage;
+use Intervention\Image\ImageServiceProvider;
use JustBetter\ImageOptimize\ServiceProvider;
-use Orchestra\Testbench\TestCase as BaseTestCase;
+use Statamic\Assets\Asset;
+use Statamic\Assets\AssetContainer;
+use Statamic\Testing\AddonTestCase;
+use Statamic\Testing\Concerns\PreventsSavingStacheItemsToDisk;
-abstract class TestCase extends BaseTestCase
+abstract class TestCase extends AddonTestCase
{
- protected function getPackageProviders($app): array
+ use InteractsWithViews;
+ use LazilyRefreshDatabase;
+ use PreventsSavingStacheItemsToDisk;
+
+ protected string $addonServiceProvider = ServiceProvider::class;
+
+ protected ?AssetContainer $assetContainer = null;
+
+ protected function getPackageProviders($app)
+ {
+ return array_merge(parent::getPackageProviders($app), [
+ ImageServiceProvider::class,
+ ]);
+ }
+
+ protected function defineEnvironment($app): void
+ {
+ $app['config']->set('app.key', 'AckfSECXIvnK5r28GVIWUAxmbBSjTsmF');
+
+ $app['config']->set('statamic.assets.image_manipulation.driver', 'gd');
+
+ $app['config']->set('filesystems.disks.assets', [
+ 'driver' => 'local',
+ 'root' => $this->fixturePath('assets'),
+ ]);
+
+ $app['config']->set('database.default', 'testbench');
+ $app['config']->set('queue.batching.database', 'testbench');
+ $app['config']->set('queue.failed.database', 'testbench');
+ $app['config']->set('database.connections.testbench', [
+ 'driver' => 'sqlite',
+ 'database' => ':memory:',
+ 'prefix' => '',
+ ]);
+ }
+
+ protected function assetContainer(): AssetContainer
{
- return [
- ServiceProvider::class,
- ];
+ if ($this->assetContainer === null) {
+ $this->assetContainer = (new AssetContainer) // @phpstan-ignore-line
+ ->handle('test_container')
+ ->disk('assets')
+ ->save();
+ }
+
+ return $this->assetContainer;
+ }
+
+ protected function fixturePath(string $file = ''): string
+ {
+ $path = __DIR__.'/__fixtures__';
+
+ if (strlen($file) > 0) {
+ $path .= '/'.$file;
+ }
+
+ return $path;
+ }
+
+ protected function createAsset(string $filename = 'test.png'): Asset
+ {
+ Storage::disk('assets')->put($filename, file_get_contents($this->fixturePath('uploads/test.png'))); // @phpstan-ignore-line
+
+ /** @var Asset $asset */
+ $asset = (new Asset)->container($this->assetContainer())->path($filename); // @phpstan-ignore-line
+ $asset->save();
+
+ return $asset;
}
}
diff --git a/tests/__fixtures__/assets/.gitignore b/tests/__fixtures__/assets/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/tests/__fixtures__/assets/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/tests/__fixtures__/content/assets/test_container.yaml b/tests/__fixtures__/content/assets/test_container.yaml
new file mode 100644
index 0000000..1bb97e5
--- /dev/null
+++ b/tests/__fixtures__/content/assets/test_container.yaml
@@ -0,0 +1 @@
+disk: assets
diff --git a/tests/__fixtures__/dev-null/.gitkeep b/tests/__fixtures__/dev-null/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/tests/__fixtures__/uploads/test.png b/tests/__fixtures__/uploads/test.png
new file mode 100644
index 0000000..1eceb0c
Binary files /dev/null and b/tests/__fixtures__/uploads/test.png differ