From fbd5aeeffa6e21b89f03c751ca21e326424dcaec Mon Sep 17 00:00:00 2001 From: enjoys Date: Fri, 27 Jun 2025 10:09:10 +0300 Subject: [PATCH 01/15] PSR-14 (Event Manager) has been added --- composer.json | 5 +++-- src/Event/AbstractUploadEvent.php | 24 ++++++++++++++++++++++++ src/Event/AfterUploadEvent.php | 15 +++++++++++++++ src/Event/BeforeUploadEvent.php | 15 +++++++++++++++ src/Event/BeforeValidationEvent.php | 16 ++++++++++++++++ src/Event/UploadErrorEvent.php | 18 ++++++++++++++++++ src/UploadProcessing.php | 26 ++++++++++++++++++++++---- 7 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 src/Event/AbstractUploadEvent.php create mode 100644 src/Event/AfterUploadEvent.php create mode 100644 src/Event/BeforeUploadEvent.php create mode 100644 src/Event/BeforeValidationEvent.php create mode 100644 src/Event/UploadErrorEvent.php diff --git a/composer.json b/composer.json index 475c69e..853fa8e 100644 --- a/composer.json +++ b/composer.json @@ -18,11 +18,12 @@ "require": { "php": "~8.2.0 | ~8.3.0 | ~8.4.0", "psr/http-message": "^1.0 | ^2.0", - "league/flysystem": "^3.30.0" + "league/flysystem": "^3.30.0", + "psr/event-dispatcher": "^1.0" }, "require-dev": { "vimeo/psalm": "^6.12.0", - "phpunit/phpunit": "^11.5.24", + "phpunit/phpunit": "^11.5.25", "infection/infection": "^0.29.14", "league/flysystem-memory": "^3.29.0", "guzzlehttp/psr7": "^2.7.1" diff --git a/src/Event/AbstractUploadEvent.php b/src/Event/AbstractUploadEvent.php new file mode 100644 index 0000000..73d0695 --- /dev/null +++ b/src/Event/AbstractUploadEvent.php @@ -0,0 +1,24 @@ +propagationStopped; + } + + public function stopPropagation(): void + { + $this->propagationStopped = true; + } +} diff --git a/src/Event/AfterUploadEvent.php b/src/Event/AfterUploadEvent.php new file mode 100644 index 0000000..5c41593 --- /dev/null +++ b/src/Event/AfterUploadEvent.php @@ -0,0 +1,15 @@ +fileInfo = new FileInfo($uploadedFile); } @@ -43,17 +50,28 @@ public function __construct( * * @param string $targetPath The target directory path (defaults to '/') * @throws FilesystemException If there's an error during file system operations + * @throws RuleException Thrown when validation fails + * @throws \Throwable */ public function upload(string $targetPath = '/'): void { - $this->validate(); - - $this->targetPath = rtrim($targetPath, '/') . '/' . $this->fileInfo->getFilename(); - $this->filesystem->writeStream($this->targetPath, $this->uploadedFile->getStream()->detach()); + try { + $this->dispatcher?->dispatch(new BeforeValidationEvent($this)); + $this->validate(); + $this->dispatcher?->dispatch(new BeforeUploadEvent($this)); + $this->targetPath = rtrim($targetPath, '/') . '/' . $this->fileInfo->getFilename(); + $this->filesystem->writeStream($this->targetPath, $this->uploadedFile->getStream()->detach()); + $this->dispatcher?->dispatch(new AfterUploadEvent($this)); + } catch (\Throwable $e) { + $this->dispatcher?->dispatch(new UploadErrorEvent($this, $e)); + throw $e; + } } /** * Validates the uploaded file against all registered rules + * + * @throws RuleException Thrown when validation fails */ private function validate(): void { From 1e473949a6df206c29a42fa2a83cab9d5bcf3730 Mon Sep 17 00:00:00 2001 From: enjoys Date: Fri, 27 Jun 2025 14:32:56 +0300 Subject: [PATCH 02/15] added tests --- tests/UploadProcessingEventTest.php | 156 ++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 tests/UploadProcessingEventTest.php diff --git a/tests/UploadProcessingEventTest.php b/tests/UploadProcessingEventTest.php new file mode 100644 index 0000000..d585462 --- /dev/null +++ b/tests/UploadProcessingEventTest.php @@ -0,0 +1,156 @@ +tmpFile = tempnam(sys_get_temp_dir(), 'testUpload'); + file_put_contents($this->tmpFile, 'Content'); + $this->filesystem = new Filesystem(new InMemoryFilesystemAdapter()); + } + + public function tearDown(): void + { + if (file_exists($this->tmpFile)) { + unlink($this->tmpFile); + } + } + + /** + * @throws FilesystemException + * @throws Throwable + * @throws Exception + */ + public function testEventsAreDispatchedInCorrectOrder(): void + { + $uploadedFile = new UploadedFile($this->tmpFile, 128, UPLOAD_ERR_OK, 'original_file_name.txt', 'plain/text'); + $dispatcher = $this->createMock(EventDispatcherInterface::class); + + $dispatchedEvents = []; + $dispatcher->method('dispatch') + ->willReturnCallback(function ($event) use (&$dispatchedEvents) { + $dispatchedEvents[] = get_class($event); + return $event; + }); + + $upload = new UploadProcessing($uploadedFile, $this->filesystem, $dispatcher); + $upload->upload(); + + $this->assertSame([ + BeforeValidationEvent::class, + BeforeUploadEvent::class, + AfterUploadEvent::class + ], $dispatchedEvents); + } + + /** + * @throws FilesystemException + * @throws Throwable + * @throws Exception + */ + public function testErrorEventIsDispatchedOnException(): void + { + $this->expectException(RuntimeException::class); + $uploadedFile = new UploadedFile($this->tmpFile, 128, UPLOAD_ERR_OK, 'original_file_name.txt', 'plain/text'); + $dispatcher = $this->createMock(EventDispatcherInterface::class); + $filesystem = $this->createMock(Filesystem::class); + $filesystem->method('writeStream')->willThrowException( + new RuntimeException('Test error') + ); + + $dispatchedEvents = []; + $dispatcher->method('dispatch') + ->willReturnCallback(function ($event) use (&$dispatchedEvents) { + $dispatchedEvents[] = get_class($event); + return $event; + }); + + $upload = new UploadProcessing($uploadedFile, $filesystem, $dispatcher); + try { + $upload->upload(); + $this->fail('Expected exception was not thrown'); + } catch (Throwable $e) { + $this->assertSame('Test error', $e->getMessage()); + $this->assertCount(3, $dispatchedEvents); + $this->assertSame([ + BeforeValidationEvent::class, + BeforeUploadEvent::class, + UploadErrorEvent::class + ], $dispatchedEvents); + throw $e; + } + } + + /** + * @throws FilesystemException + * @throws Throwable + */ + public function testWorksWithoutDispatcher(): void + { + $uploadedFile = new UploadedFile($this->tmpFile, 128, UPLOAD_ERR_OK, 'original_file_name.txt', 'plain/text'); + $upload = new UploadProcessing($uploadedFile, $this->filesystem); + $upload->upload(); + $this->assertNotNull($upload->getTargetPath()); + } + + /** + * @throws FilesystemException + * @throws Throwable + */ + public function testEventContainsCorrectContext(): void + { + $uploadedFile = new UploadedFile($this->tmpFile, 128, UPLOAD_ERR_OK, 'original_file_name.txt', 'plain/text'); + $dispatcher = new class implements EventDispatcherInterface { + + public array $dispatchedEvents = []; + + public function dispatch(object $event): object + { + $this->dispatchedEvents[] = $event; + return $event; + } + }; + + $upload = new UploadProcessing($uploadedFile, $this->filesystem, $dispatcher); + $upload->setFilename('test.txt'); + $upload->upload('/test/path'); + + $this->assertCount(3, $dispatcher->dispatchedEvents); + + /** @var BeforeValidationEvent $beforeValidationEvent */ + $beforeValidationEvent = $dispatcher->dispatchedEvents[0]; + $this->assertSame($upload, $beforeValidationEvent->uploadProcessing); + + /** @var BeforeUploadEvent $beforeUploadEvent */ + $beforeUploadEvent = $dispatcher->dispatchedEvents[1]; + $this->assertSame($upload, $beforeUploadEvent->uploadProcessing); + + /** @var AfterUploadEvent $afterUploadEvent */ + $afterUploadEvent = $dispatcher->dispatchedEvents[2]; + $this->assertSame('/test/path/test.txt', $afterUploadEvent->uploadProcessing->getTargetPath()); + } +} From fd47b2490b6c4736391e30d6a788bfb7e00c9d4c Mon Sep 17 00:00:00 2001 From: enjoys Date: Fri, 27 Jun 2025 14:33:17 +0300 Subject: [PATCH 03/15] improved variables name --- src/Event/AfterUploadEvent.php | 2 +- src/Event/BeforeUploadEvent.php | 2 +- src/Event/BeforeValidationEvent.php | 2 +- src/Event/UploadErrorEvent.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Event/AfterUploadEvent.php b/src/Event/AfterUploadEvent.php index 5c41593..de16907 100644 --- a/src/Event/AfterUploadEvent.php +++ b/src/Event/AfterUploadEvent.php @@ -9,7 +9,7 @@ final class AfterUploadEvent extends AbstractUploadEvent { - public function __construct(public readonly UploadProcessing $file) + public function __construct(public readonly UploadProcessing $uploadProcessing) { } } diff --git a/src/Event/BeforeUploadEvent.php b/src/Event/BeforeUploadEvent.php index 22c844e..1d17a0b 100644 --- a/src/Event/BeforeUploadEvent.php +++ b/src/Event/BeforeUploadEvent.php @@ -9,7 +9,7 @@ final class BeforeUploadEvent extends AbstractUploadEvent { - public function __construct(public readonly UploadProcessing $file) + public function __construct(public readonly UploadProcessing $uploadProcessing) { } } diff --git a/src/Event/BeforeValidationEvent.php b/src/Event/BeforeValidationEvent.php index 302e356..d39f072 100644 --- a/src/Event/BeforeValidationEvent.php +++ b/src/Event/BeforeValidationEvent.php @@ -10,7 +10,7 @@ final class BeforeValidationEvent extends AbstractUploadEvent { - public function __construct(public readonly UploadProcessing $file) + public function __construct(public readonly UploadProcessing $uploadProcessing) { } } diff --git a/src/Event/UploadErrorEvent.php b/src/Event/UploadErrorEvent.php index f77fa60..5f71576 100644 --- a/src/Event/UploadErrorEvent.php +++ b/src/Event/UploadErrorEvent.php @@ -11,7 +11,7 @@ final class UploadErrorEvent extends AbstractUploadEvent { public function __construct( - public readonly UploadProcessing $file, + public readonly UploadProcessing $uploadProcessing, public readonly \Throwable $exception ) { } From fdc32e881ac0a6cc943211a81e192fd9ce1f7ab4 Mon Sep 17 00:00:00 2001 From: enjoys Date: Fri, 27 Jun 2025 14:33:28 +0300 Subject: [PATCH 04/15] req symfony/var-dumper --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index 853fa8e..e3fbe4f 100644 --- a/composer.json +++ b/composer.json @@ -26,6 +26,7 @@ "phpunit/phpunit": "^11.5.25", "infection/infection": "^0.29.14", "league/flysystem-memory": "^3.29.0", + "symfony/var-dumper": "^6.0 | ^7.0", "guzzlehttp/psr7": "^2.7.1" }, "autoload": { From 83040c670bed3515cfcd46a65ffcedf941eb6cbc Mon Sep 17 00:00:00 2001 From: enjoys Date: Fri, 27 Jun 2025 14:41:35 +0300 Subject: [PATCH 05/15] improved tests --- tests/UploadProcessingEventTest.php | 69 +++++++++++++++++------------ 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/tests/UploadProcessingEventTest.php b/tests/UploadProcessingEventTest.php index d585462..bf58593 100644 --- a/tests/UploadProcessingEventTest.php +++ b/tests/UploadProcessingEventTest.php @@ -1,5 +1,4 @@ filesystem = new Filesystem(new InMemoryFilesystemAdapter()); } - public function tearDown(): void + protected function tearDown(): void { if (file_exists($this->tmpFile)) { unlink($this->tmpFile); @@ -47,60 +46,63 @@ public function tearDown(): void */ public function testEventsAreDispatchedInCorrectOrder(): void { - $uploadedFile = new UploadedFile($this->tmpFile, 128, UPLOAD_ERR_OK, 'original_file_name.txt', 'plain/text'); + $uploadedFile = $this->createUploadedFile(); $dispatcher = $this->createMock(EventDispatcherInterface::class); $dispatchedEvents = []; $dispatcher->method('dispatch') ->willReturnCallback(function ($event) use (&$dispatchedEvents) { - $dispatchedEvents[] = get_class($event); + $dispatchedEvents[] = $event; return $event; }); $upload = new UploadProcessing($uploadedFile, $this->filesystem, $dispatcher); $upload->upload(); - $this->assertSame([ - BeforeValidationEvent::class, - BeforeUploadEvent::class, - AfterUploadEvent::class - ], $dispatchedEvents); + $this->assertCount(3, $dispatchedEvents); + $this->assertInstanceOf(BeforeValidationEvent::class, $dispatchedEvents[0]); + $this->assertInstanceOf(BeforeUploadEvent::class, $dispatchedEvents[1]); + $this->assertInstanceOf(AfterUploadEvent::class, $dispatchedEvents[2]); } /** - * @throws FilesystemException - * @throws Throwable * @throws Exception + * @throws Throwable */ public function testErrorEventIsDispatchedOnException(): void { $this->expectException(RuntimeException::class); - $uploadedFile = new UploadedFile($this->tmpFile, 128, UPLOAD_ERR_OK, 'original_file_name.txt', 'plain/text'); + $uploadedFile = $this->createUploadedFile(); $dispatcher = $this->createMock(EventDispatcherInterface::class); + $filesystem = $this->createMock(Filesystem::class); - $filesystem->method('writeStream')->willThrowException( - new RuntimeException('Test error') - ); + $filesystem->method('writeStream') + ->willThrowException(new RuntimeException('Test error')); $dispatchedEvents = []; $dispatcher->method('dispatch') ->willReturnCallback(function ($event) use (&$dispatchedEvents) { - $dispatchedEvents[] = get_class($event); + $dispatchedEvents[] = $event; return $event; }); $upload = new UploadProcessing($uploadedFile, $filesystem, $dispatcher); + try { $upload->upload(); $this->fail('Expected exception was not thrown'); - } catch (Throwable $e) { + } catch (\Throwable $e) { $this->assertSame('Test error', $e->getMessage()); + $this->assertCount(3, $dispatchedEvents); - $this->assertSame([ - BeforeValidationEvent::class, - BeforeUploadEvent::class, - UploadErrorEvent::class - ], $dispatchedEvents); + $this->assertInstanceOf(BeforeValidationEvent::class, $dispatchedEvents[0]); + $this->assertInstanceOf(BeforeUploadEvent::class, $dispatchedEvents[1]); + $this->assertInstanceOf(UploadErrorEvent::class, $dispatchedEvents[2]); + + /** @var UploadErrorEvent $errorEvent */ + $errorEvent = $dispatchedEvents[2]; + $this->assertSame($upload, $errorEvent->uploadProcessing); + $this->assertSame($e, $errorEvent->exception); throw $e; } } @@ -111,10 +113,12 @@ public function testErrorEventIsDispatchedOnException(): void */ public function testWorksWithoutDispatcher(): void { - $uploadedFile = new UploadedFile($this->tmpFile, 128, UPLOAD_ERR_OK, 'original_file_name.txt', 'plain/text'); + $uploadedFile = $this->createUploadedFile(); $upload = new UploadProcessing($uploadedFile, $this->filesystem); $upload->upload(); + $this->assertNotNull($upload->getTargetPath()); + $this->assertTrue($this->filesystem->fileExists($upload->getTargetPath())); } /** @@ -123,9 +127,8 @@ public function testWorksWithoutDispatcher(): void */ public function testEventContainsCorrectContext(): void { - $uploadedFile = new UploadedFile($this->tmpFile, 128, UPLOAD_ERR_OK, 'original_file_name.txt', 'plain/text'); + $uploadedFile = $this->createUploadedFile(); $dispatcher = new class implements EventDispatcherInterface { - public array $dispatchedEvents = []; public function dispatch(object $event): object @@ -141,16 +144,24 @@ public function dispatch(object $event): object $this->assertCount(3, $dispatcher->dispatchedEvents); - /** @var BeforeValidationEvent $beforeValidationEvent */ $beforeValidationEvent = $dispatcher->dispatchedEvents[0]; $this->assertSame($upload, $beforeValidationEvent->uploadProcessing); - /** @var BeforeUploadEvent $beforeUploadEvent */ $beforeUploadEvent = $dispatcher->dispatchedEvents[1]; $this->assertSame($upload, $beforeUploadEvent->uploadProcessing); - /** @var AfterUploadEvent $afterUploadEvent */ $afterUploadEvent = $dispatcher->dispatchedEvents[2]; $this->assertSame('/test/path/test.txt', $afterUploadEvent->uploadProcessing->getTargetPath()); } + + private function createUploadedFile(?string $clientFilename = null, ?string $mediaType = null): UploadedFile + { + return new UploadedFile( + $this->tmpFile, + 128, + UPLOAD_ERR_OK, + $clientFilename ?? 'original_file_name.txt', + $mediaType ?? 'plain/text' + ); + } } From da94e5246ec2db5d735b95c67335206a647dc7c7 Mon Sep 17 00:00:00 2001 From: enjoys Date: Fri, 27 Jun 2025 17:57:07 +0300 Subject: [PATCH 06/15] improved tests `testEventPropagation` --- src/Event/AbstractUploadEvent.php | 2 -- src/Event/AfterUploadEvent.php | 1 - src/Event/BeforeUploadEvent.php | 1 - src/Event/BeforeValidationEvent.php | 2 -- src/Event/UploadErrorEvent.php | 2 -- tests/UploadProcessingEventTest.php | 46 +++++++++++++++++++++++++++++ 6 files changed, 46 insertions(+), 8 deletions(-) diff --git a/src/Event/AbstractUploadEvent.php b/src/Event/AbstractUploadEvent.php index 73d0695..dea1b57 100644 --- a/src/Event/AbstractUploadEvent.php +++ b/src/Event/AbstractUploadEvent.php @@ -2,10 +2,8 @@ declare(strict_types=1); - namespace Enjoys\Upload\Event; - use Psr\EventDispatcher\StoppableEventInterface; abstract class AbstractUploadEvent implements StoppableEventInterface diff --git a/src/Event/AfterUploadEvent.php b/src/Event/AfterUploadEvent.php index de16907..6eed72e 100644 --- a/src/Event/AfterUploadEvent.php +++ b/src/Event/AfterUploadEvent.php @@ -4,7 +4,6 @@ namespace Enjoys\Upload\Event; -use Enjoys\Upload\Event\AbstractUploadEvent; use Enjoys\Upload\UploadProcessing; final class AfterUploadEvent extends AbstractUploadEvent diff --git a/src/Event/BeforeUploadEvent.php b/src/Event/BeforeUploadEvent.php index 1d17a0b..d3e2981 100644 --- a/src/Event/BeforeUploadEvent.php +++ b/src/Event/BeforeUploadEvent.php @@ -4,7 +4,6 @@ namespace Enjoys\Upload\Event; -use Enjoys\Upload\Event\AbstractUploadEvent; use Enjoys\Upload\UploadProcessing; final class BeforeUploadEvent extends AbstractUploadEvent diff --git a/src/Event/BeforeValidationEvent.php b/src/Event/BeforeValidationEvent.php index d39f072..afe281a 100644 --- a/src/Event/BeforeValidationEvent.php +++ b/src/Event/BeforeValidationEvent.php @@ -4,9 +4,7 @@ namespace Enjoys\Upload\Event; -use Enjoys\Upload\Event\AbstractUploadEvent; use Enjoys\Upload\UploadProcessing; -use Psr\Http\Message\UploadedFileInterface; final class BeforeValidationEvent extends AbstractUploadEvent { diff --git a/src/Event/UploadErrorEvent.php b/src/Event/UploadErrorEvent.php index 5f71576..c107334 100644 --- a/src/Event/UploadErrorEvent.php +++ b/src/Event/UploadErrorEvent.php @@ -2,10 +2,8 @@ declare(strict_types=1); - namespace Enjoys\Upload\Event; - use Enjoys\Upload\UploadProcessing; final class UploadErrorEvent extends AbstractUploadEvent diff --git a/tests/UploadProcessingEventTest.php b/tests/UploadProcessingEventTest.php index bf58593..38f72fe 100644 --- a/tests/UploadProcessingEventTest.php +++ b/tests/UploadProcessingEventTest.php @@ -3,10 +3,12 @@ namespace Enjoys\Tests\Upload; +use Enjoys\Upload\Event\AbstractUploadEvent; use Enjoys\Upload\Event\AfterUploadEvent; use Enjoys\Upload\Event\BeforeUploadEvent; use Enjoys\Upload\Event\BeforeValidationEvent; use Enjoys\Upload\Event\UploadErrorEvent; +use Enjoys\Upload\FileInfo; use Enjoys\Upload\UploadProcessing; use GuzzleHttp\Psr7\UploadedFile; use League\Flysystem\Filesystem; @@ -20,6 +22,11 @@ use Throwable; #[CoversClass(UploadProcessing::class)] +#[CoversClass(FileInfo::class)] +#[CoversClass(BeforeValidationEvent::class)] +#[CoversClass(BeforeUploadEvent::class)] +#[CoversClass(AfterUploadEvent::class)] +#[CoversClass(UploadErrorEvent::class)] final class UploadProcessingEventTest extends TestCase { private string $tmpFile; @@ -164,4 +171,43 @@ private function createUploadedFile(?string $clientFilename = null, ?string $med $mediaType ?? 'plain/text' ); } + + public function testEventPropagation(): void + { + $event = new class extends AbstractUploadEvent {}; + $this->assertFalse($event->isPropagationStopped()); + $event->stopPropagation(); + $this->assertTrue($event->isPropagationStopped()); + } + + public function testEventPropagationStopping(): void + { + + $dispatcher = new class implements EventDispatcherInterface { + public array $dispatchedEvents = []; + + public function dispatch(object $event): object + { + if ($event->isPropagationStopped()) { + return $event; + } + + $this->dispatchedEvents[] = $event; + return $event; + } + }; + + $uploadProcessing = new UploadProcessing($this->createUploadedFile(), $this->filesystem, $dispatcher); + + $event1 = new AfterUploadEvent($uploadProcessing); + $event2 = new AfterUploadEvent($uploadProcessing); + + $event1->stopPropagation(); + + $dispatcher->dispatch($event1); + $dispatcher->dispatch($event2); + + $this->assertCount(1, $dispatcher->dispatchedEvents); + $this->assertSame($event2, $dispatcher->dispatchedEvents[0]); + } } From a28196222acfe64a0a2a7c0b8c6157be6245ba1b Mon Sep 17 00:00:00 2001 From: enjoys Date: Fri, 27 Jun 2025 18:26:04 +0300 Subject: [PATCH 07/15] Update README.md --- README.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/README.md b/README.md index 2fa1080..32dacdf 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,49 @@ $rule->allow('image/*') // All image types ->allow('application/pdf') // PDF files ->allow('*/vnd.openxmlformats-officedocument.*'); // Office documents ``` +### Event System + +The library provides PSR-14 compatible events: + +#### Available Events: +- **`BeforeValidationEvent`** - Dispatched before validation starts +- **`BeforeUploadEvent`** - Dispatched after validation, before file upload +- **`AfterUploadEvent`** - Dispatched after successful file upload +- **`UploadErrorEvent`** - Dispatched when any error occurs + +#### Usage Example: +```php +use Enjoys\Upload\Event\AfterUploadEvent; +use Psr\EventDispatcher\EventDispatcherInterface; + +/** @var EventDispatcherInterface $dispatcher */ + +// Initialize with event dispatcher +$upload = new UploadProcessing($uploadedFile, $filesystem, $dispatcher); + +// Add event listener +$dispatcher->addListener( + AfterUploadEvent::class, + function (AfterUploadEvent $event) { + logger()->info("File uploaded to: " . $event->uploadProcessing->getTargetPath()); + } +); + +$upload->upload(); +``` + +#### Event Propagation: +All events implement `StoppableEventInterface`. To stop further processing: +```php +$dispatcher->addListener( + BeforeUploadEvent::class, + function (BeforeUploadEvent $event) { + if ($shouldStop) { + $event->stopPropagation(); // Stops other listeners + } + } +); +``` ### API Reference From 28908f8f0ec7f6884d993b20fe9f54f5c2709171 Mon Sep 17 00:00:00 2001 From: enjoys Date: Fri, 27 Jun 2025 18:41:51 +0300 Subject: [PATCH 08/15] Update @phpdoc --- src/Event/AbstractUploadEvent.php | 24 ++++++++++++++++++++++++ src/Event/AfterUploadEvent.php | 15 +++++++++++++++ src/Event/BeforeUploadEvent.php | 14 ++++++++++++++ src/Event/BeforeValidationEvent.php | 14 ++++++++++++++ src/Event/UploadErrorEvent.php | 20 +++++++++++++++++++- src/UploadProcessing.php | 8 +++++--- 6 files changed, 91 insertions(+), 4 deletions(-) diff --git a/src/Event/AbstractUploadEvent.php b/src/Event/AbstractUploadEvent.php index dea1b57..daf5268 100644 --- a/src/Event/AbstractUploadEvent.php +++ b/src/Event/AbstractUploadEvent.php @@ -6,15 +6,39 @@ use Psr\EventDispatcher\StoppableEventInterface; +/** + * Base abstract class for all upload-related events + * + * Provides common functionality for event propagation control + * according to PSR-14 (Event Dispatcher) standard. + * + * All concrete upload events should extend this class to maintain + * consistent behavior across the upload event system. + */ abstract class AbstractUploadEvent implements StoppableEventInterface { + /** + * @var bool Flag indicating whether event propagation is stopped + */ private bool $propagationStopped = false; + /** + * Checks whether event propagation is stopped + * + * @return bool True if event propagation is stopped, false otherwise + */ public function isPropagationStopped(): bool { return $this->propagationStopped; } + /** + * Stops the event propagation + * + * When called, prevents the event from being passed to additional listeners. + * This is useful when a listener has handled the event and wants to prevent + * other listeners from processing it further. + */ public function stopPropagation(): void { $this->propagationStopped = true; diff --git a/src/Event/AfterUploadEvent.php b/src/Event/AfterUploadEvent.php index 6eed72e..67c76cc 100644 --- a/src/Event/AfterUploadEvent.php +++ b/src/Event/AfterUploadEvent.php @@ -6,8 +6,23 @@ use Enjoys\Upload\UploadProcessing; +/** + * Event dispatched after a file has been successfully uploaded and processed + * + * This event provides access to the upload processing instance, allowing listeners + * to retrieve information about the uploaded file(s), storage details, and any + * processing results. + */ final class AfterUploadEvent extends AbstractUploadEvent { + /** + * @param UploadProcessing $uploadProcessing The upload processing instance containing + * details about the completed upload operation, including: + * - Processed file metadata + * - Storage information + * - Any transformations applied + * - Upload status and results + */ public function __construct(public readonly UploadProcessing $uploadProcessing) { } diff --git a/src/Event/BeforeUploadEvent.php b/src/Event/BeforeUploadEvent.php index d3e2981..869fa4d 100644 --- a/src/Event/BeforeUploadEvent.php +++ b/src/Event/BeforeUploadEvent.php @@ -6,8 +6,22 @@ use Enjoys\Upload\UploadProcessing; +/** + * Event dispatched before file upload processing begins + * + * This event allows listeners to modify upload parameters or perform validation + * before the actual file processing occurs. The upload can be aborted by throwing + * an exception from an event listener. + */ final class BeforeUploadEvent extends AbstractUploadEvent { + /** + * @param UploadProcessing $uploadProcessing The upload processing instance containing: + * - File metadata (name, size, type) + * - Target storage configuration + * - Processing options + * - Validation rules + */ public function __construct(public readonly UploadProcessing $uploadProcessing) { } diff --git a/src/Event/BeforeValidationEvent.php b/src/Event/BeforeValidationEvent.php index afe281a..3652794 100644 --- a/src/Event/BeforeValidationEvent.php +++ b/src/Event/BeforeValidationEvent.php @@ -6,8 +6,22 @@ use Enjoys\Upload\UploadProcessing; +/** + * Event dispatched before file validation occurs + * + * This event allows listeners to modify validation rules or perform + * custom pre-validation checks before the standard validation process. + * The upload can be aborted by throwing an exception from an event listener. + */ final class BeforeValidationEvent extends AbstractUploadEvent { + /** + * @param UploadProcessing $uploadProcessing The upload processing instance containing: + * - File metadata (name, size, temporary path) + * - Current validation rules + * - Upload configuration + * - User-defined validation callbacks + */ public function __construct(public readonly UploadProcessing $uploadProcessing) { } diff --git a/src/Event/UploadErrorEvent.php b/src/Event/UploadErrorEvent.php index c107334..77d8d16 100644 --- a/src/Event/UploadErrorEvent.php +++ b/src/Event/UploadErrorEvent.php @@ -5,12 +5,30 @@ namespace Enjoys\Upload\Event; use Enjoys\Upload\UploadProcessing; +use Throwable; +/** + * Event dispatched when an error occurs during file upload processing + * + * This event provides access to both the upload processing instance and the exception + * that caused the failure, allowing for error handling, logging, or recovery attempts. + * Common error scenarios include: + * - File validation failures + * - Filesystem errors (permissions, quota exceeded) + * - Processing errors (image manipulation, etc.) + * - Network errors (for remote storage) + */ final class UploadErrorEvent extends AbstractUploadEvent { + /** + * @param UploadProcessing $uploadProcessing The upload processing instance containing + * details about the failed upload operation + * @param Throwable $exception The exception that caused the upload to fail + * with detailed error information and stack trace + */ public function __construct( public readonly UploadProcessing $uploadProcessing, - public readonly \Throwable $exception + public readonly Throwable $exception ) { } } diff --git a/src/UploadProcessing.php b/src/UploadProcessing.php index 4d9296f..b41d971 100644 --- a/src/UploadProcessing.php +++ b/src/UploadProcessing.php @@ -13,12 +13,13 @@ use League\Flysystem\FilesystemException; use Psr\EventDispatcher\EventDispatcherInterface; use Psr\Http\Message\UploadedFileInterface; +use Throwable; final class UploadProcessing { /** - * @var string|null Final storage path (null until file is uploaded) + * @var string|null Final storage path (null until a file is uploaded) */ private ?string $targetPath = null; @@ -36,6 +37,7 @@ final class UploadProcessing * @param UploadedFileInterface $uploadedFile The PSR-7 uploaded file to process * @param Filesystem $filesystem Flysystem instance that provides filesystem abstraction * (supports local, FTP, S3, and other storage systems) + * @param EventDispatcherInterface|null $dispatcher Optional event dispatcher for handling upload-related events */ public function __construct( private readonly UploadedFileInterface $uploadedFile, @@ -51,7 +53,7 @@ public function __construct( * @param string $targetPath The target directory path (defaults to '/') * @throws FilesystemException If there's an error during file system operations * @throws RuleException Thrown when validation fails - * @throws \Throwable + * @throws Throwable */ public function upload(string $targetPath = '/'): void { @@ -62,7 +64,7 @@ public function upload(string $targetPath = '/'): void $this->targetPath = rtrim($targetPath, '/') . '/' . $this->fileInfo->getFilename(); $this->filesystem->writeStream($this->targetPath, $this->uploadedFile->getStream()->detach()); $this->dispatcher?->dispatch(new AfterUploadEvent($this)); - } catch (\Throwable $e) { + } catch (Throwable $e) { $this->dispatcher?->dispatch(new UploadErrorEvent($this, $e)); throw $e; } From ca0f51bee437ebc9b8ad6f9ca46ddb102328d4c8 Mon Sep 17 00:00:00 2001 From: enjoys Date: Fri, 27 Jun 2025 22:53:28 +0300 Subject: [PATCH 09/15] fix MissingOverrideAttribute --- src/Event/AbstractUploadEvent.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Event/AbstractUploadEvent.php b/src/Event/AbstractUploadEvent.php index daf5268..d42c08a 100644 --- a/src/Event/AbstractUploadEvent.php +++ b/src/Event/AbstractUploadEvent.php @@ -27,6 +27,7 @@ abstract class AbstractUploadEvent implements StoppableEventInterface * * @return bool True if event propagation is stopped, false otherwise */ + #[\Override] public function isPropagationStopped(): bool { return $this->propagationStopped; From 6bd6061b3a11813369bad334063eb46de64339b4 Mon Sep 17 00:00:00 2001 From: enjoys Date: Sat, 28 Jun 2025 09:29:20 +0300 Subject: [PATCH 10/15] fix syntax --- src/UploadProcessing.php | 74 ++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/src/UploadProcessing.php b/src/UploadProcessing.php index a836c8a..d3ffa97 100644 --- a/src/UploadProcessing.php +++ b/src/UploadProcessing.php @@ -56,26 +56,24 @@ public function __construct( * @throws Throwable */ public function upload(string $targetPath = '/'): void - + { + $this->dispatcher?->dispatch(new BeforeValidationEvent($this)); + $this->validate(); + + $this->dispatcher?->dispatch(new BeforeUploadEvent($this)); + $this->targetPath = rtrim($targetPath, '/') . '/' . $this->fileInfo->getFilename(); + + $resource = $this->uploadedFile->getStream()->detach(); try { - $this->dispatcher?->dispatch(new BeforeValidationEvent($this)); - $this->validate(); - - $this->dispatcher?->dispatch(new BeforeUploadEvent($this)); - $this->targetPath = rtrim($targetPath, '/') . '/' . $this->fileInfo->getFilename(); - - $resource = $this->uploadedFile->getStream()->detach(); - try { - $this->filesystem->writeStream($this->targetPath, $resource); - $this->dispatcher?->dispatch(new AfterUploadEvent($this)); - } finally { - if (is_resource($resource)) { - fclose($resource); - } - } catch (Throwable $e) { - $this->dispatcher?->dispatch(new UploadErrorEvent($this, $e)); - throw $e; - } + $this->filesystem->writeStream($this->targetPath, $resource); + $this->dispatcher?->dispatch(new AfterUploadEvent($this)); + } catch (Throwable $e) { + $this->dispatcher?->dispatch(new UploadErrorEvent($this, $e)); + throw $e; + } finally { + if (is_resource($resource)) { + fclose($resource); + } } } @@ -84,7 +82,8 @@ public function upload(string $targetPath = '/'): void * * @throws RuleException Thrown when validation fails */ - private function validate(): void + private + function validate(): void { foreach ($this->rules as $rule) { $rule->check($this->getUploadedFile()); @@ -97,8 +96,10 @@ private function validate(): void * * @param string $filename The desired filename */ - public function setFilename(string $filename): void - { + public + function setFilename( + string $filename + ): void { $this->fileInfo->setFilename($filename); } @@ -107,7 +108,8 @@ public function setFilename(string $filename): void * * @return UploadedFileInterface UploadedFileInterface The PSR-7 compliant uploaded file object */ - public function getUploadedFile(): UploadedFileInterface + public + function getUploadedFile(): UploadedFileInterface { return $this->uploadedFile; } @@ -117,7 +119,8 @@ public function getUploadedFile(): UploadedFileInterface * * @return string|null The target path or null if not uploaded yet */ - public function getTargetPath(): ?string + public + function getTargetPath(): ?string { return $this->targetPath; } @@ -127,7 +130,8 @@ public function getTargetPath(): ?string * * @return Filesystem The filesystem instance */ - public function getFilesystem(): Filesystem + public + function getFilesystem(): Filesystem { return $this->filesystem; } @@ -137,7 +141,8 @@ public function getFilesystem(): Filesystem * * @return FileInfo The file information instance */ - public function getFileInfo(): FileInfo + public + function getFileInfo(): FileInfo { return $this->fileInfo; } @@ -147,8 +152,10 @@ public function getFileInfo(): FileInfo * * @param RuleInterface $rule The rule to add */ - public function addRule(RuleInterface $rule): void - { + public + function addRule( + RuleInterface $rule + ): void { $this->rules[] = $rule; } @@ -157,8 +164,10 @@ public function addRule(RuleInterface $rule): void * * @param RuleInterface[] $rules Array of rules to add */ - public function addRules(array $rules): void - { + public + function addRules( + array $rules + ): void { $this->rules = array_merge($this->rules, $rules); } @@ -167,10 +176,9 @@ public function addRules(array $rules): void * * @return RuleInterface[] Array of validation rules */ - public function getRules(): array + public + function getRules(): array { return $this->rules; } - - } From 147f9417d630ca426efb196cc4897a507ca408f7 Mon Sep 17 00:00:00 2001 From: enjoys Date: Sat, 28 Jun 2025 09:43:12 +0300 Subject: [PATCH 11/15] ci --- src/UploadProcessing.php | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/src/UploadProcessing.php b/src/UploadProcessing.php index d3ffa97..ef15d51 100644 --- a/src/UploadProcessing.php +++ b/src/UploadProcessing.php @@ -82,8 +82,7 @@ public function upload(string $targetPath = '/'): void * * @throws RuleException Thrown when validation fails */ - private - function validate(): void + private function validate(): void { foreach ($this->rules as $rule) { $rule->check($this->getUploadedFile()); @@ -96,10 +95,8 @@ function validate(): void * * @param string $filename The desired filename */ - public - function setFilename( - string $filename - ): void { + public function setFilename(string $filename): void + { $this->fileInfo->setFilename($filename); } @@ -108,8 +105,7 @@ function setFilename( * * @return UploadedFileInterface UploadedFileInterface The PSR-7 compliant uploaded file object */ - public - function getUploadedFile(): UploadedFileInterface + public function getUploadedFile(): UploadedFileInterface { return $this->uploadedFile; } @@ -119,8 +115,7 @@ function getUploadedFile(): UploadedFileInterface * * @return string|null The target path or null if not uploaded yet */ - public - function getTargetPath(): ?string + public function getTargetPath(): ?string { return $this->targetPath; } @@ -130,8 +125,7 @@ function getTargetPath(): ?string * * @return Filesystem The filesystem instance */ - public - function getFilesystem(): Filesystem + public function getFilesystem(): Filesystem { return $this->filesystem; } @@ -141,8 +135,7 @@ function getFilesystem(): Filesystem * * @return FileInfo The file information instance */ - public - function getFileInfo(): FileInfo + public function getFileInfo(): FileInfo { return $this->fileInfo; } @@ -152,10 +145,8 @@ function getFileInfo(): FileInfo * * @param RuleInterface $rule The rule to add */ - public - function addRule( - RuleInterface $rule - ): void { + public function addRule(RuleInterface $rule): void + { $this->rules[] = $rule; } @@ -164,10 +155,8 @@ function addRule( * * @param RuleInterface[] $rules Array of rules to add */ - public - function addRules( - array $rules - ): void { + public function addRules(array $rules): void + { $this->rules = array_merge($this->rules, $rules); } @@ -176,8 +165,7 @@ function addRules( * * @return RuleInterface[] Array of validation rules */ - public - function getRules(): array + public function getRules(): array { return $this->rules; } From b70953598f00c7692b65f0106c22da21a01fce16 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sat, 28 Jun 2025 08:58:38 +0000 Subject: [PATCH 12/15] Apply PHP-CS-Fixer fixes [skip ci] --- .php-cs-fixer.cache | 2 +- tests/UploadProcessingEventTest.php | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.php-cs-fixer.cache b/.php-cs-fixer.cache index bb86369..45583a5 100644 --- a/.php-cs-fixer.cache +++ b/.php-cs-fixer.cache @@ -1 +1 @@ -{"php":"8.2.19","version":"3.75.0","indent":" ","lineEnding":"\n","rules":{"binary_operator_spaces":{"default":"at_least_single_space"},"blank_line_after_opening_tag":true,"blank_line_between_import_groups":true,"blank_lines_before_namespace":true,"braces_position":{"allow_single_line_empty_anonymous_classes":true},"class_definition":{"inline_constructor_arguments":false,"space_before_parenthesis":true},"compact_nullable_type_declaration":true,"declare_equal_normalize":true,"lowercase_cast":true,"lowercase_static_reference":true,"new_with_parentheses":true,"no_blank_lines_after_class_opening":true,"no_extra_blank_lines":{"tokens":["use"]},"no_leading_import_slash":true,"no_whitespace_in_blank_line":true,"ordered_class_elements":{"order":["use_trait"]},"ordered_imports":{"imports_order":["class","function","const"],"sort_algorithm":"none"},"return_type_declaration":true,"short_scalar_cast":true,"single_import_per_statement":{"group_to_single_imports":false},"single_space_around_construct":{"constructs_followed_by_a_single_space":["abstract","as","case","catch","class","const_import","do","else","elseif","final","finally","for","foreach","function","function_import","if","insteadof","interface","namespace","new","private","protected","public","static","switch","trait","try","use","use_lambda","while"],"constructs_preceded_by_a_single_space":["as","else","elseif","use_lambda"]},"single_trait_insert_per_statement":true,"ternary_operator_spaces":true,"unary_operator_spaces":{"only_dec_inc":true},"visibility_required":true,"blank_line_after_namespace":true,"constant_case":true,"control_structure_braces":true,"control_structure_continuation_position":true,"elseif":true,"function_declaration":true,"indentation_type":true,"line_ending":true,"lowercase_keywords":true,"method_argument_space":{"attribute_placement":"ignore","on_multiline":"ensure_fully_multiline"},"no_break_comment":true,"no_closing_tag":true,"no_multiple_statements_per_line":true,"no_space_around_double_colon":true,"no_spaces_after_function_name":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":{"elements":["property"]},"single_line_after_imports":true,"spaces_inside_parentheses":true,"statement_indentation":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"encoding":true,"full_opening_tag":true},"hashes":{"src\/Exception\/RuleException.php":"0f48d4b0d809e8eab61416c2db16a7d8","src\/FileInfo.php":"92199a788c035eee744222d874975264","src\/UploadProcessing.php":"d071d78696edfb09f8087fba2d2fe0ce","src\/RuleInterface.php":"510ec2377e44bc9cd60734290b78a182","src\/Rule\/Extension.php":"91951f96a6b9a0880fb555c0a16cec54","src\/Rule\/MediaType.php":"2a1e550418cdc2041a8cdbace9ff6375","src\/Rule\/Size.php":"80e2e7c2888a6e79b6cf71ab8e6c80e6","tests\/FileInfoTest.php":"75ad22380821d20a861e036706f70333","tests\/UploadProcessingTest.php":"6fda40150d71be7fe67c61d154f74233","tests\/Rule\/SizeTest.php":"67f50eca6d49ff1969f14adee342f6f9","tests\/Rule\/ExtensionTest.php":"5f5adc4bbe15b6c2ce19320df3c377c9","tests\/Rule\/MediaTypeTest.php":"ac581940014eb72cb2f6bd75ee28104f"}} \ No newline at end of file +{"php":"8.2.19","version":"3.75.0","indent":" ","lineEnding":"\n","rules":{"binary_operator_spaces":{"default":"at_least_single_space"},"blank_line_after_opening_tag":true,"blank_line_between_import_groups":true,"blank_lines_before_namespace":true,"braces_position":{"allow_single_line_empty_anonymous_classes":true},"class_definition":{"inline_constructor_arguments":false,"space_before_parenthesis":true},"compact_nullable_type_declaration":true,"declare_equal_normalize":true,"lowercase_cast":true,"lowercase_static_reference":true,"new_with_parentheses":true,"no_blank_lines_after_class_opening":true,"no_extra_blank_lines":{"tokens":["use"]},"no_leading_import_slash":true,"no_whitespace_in_blank_line":true,"ordered_class_elements":{"order":["use_trait"]},"ordered_imports":{"imports_order":["class","function","const"],"sort_algorithm":"none"},"return_type_declaration":true,"short_scalar_cast":true,"single_import_per_statement":{"group_to_single_imports":false},"single_space_around_construct":{"constructs_followed_by_a_single_space":["abstract","as","case","catch","class","const_import","do","else","elseif","final","finally","for","foreach","function","function_import","if","insteadof","interface","namespace","new","private","protected","public","static","switch","trait","try","use","use_lambda","while"],"constructs_preceded_by_a_single_space":["as","else","elseif","use_lambda"]},"single_trait_insert_per_statement":true,"ternary_operator_spaces":true,"unary_operator_spaces":{"only_dec_inc":true},"visibility_required":true,"blank_line_after_namespace":true,"constant_case":true,"control_structure_braces":true,"control_structure_continuation_position":true,"elseif":true,"function_declaration":true,"indentation_type":true,"line_ending":true,"lowercase_keywords":true,"method_argument_space":{"attribute_placement":"ignore","on_multiline":"ensure_fully_multiline"},"no_break_comment":true,"no_closing_tag":true,"no_multiple_statements_per_line":true,"no_space_around_double_colon":true,"no_spaces_after_function_name":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":{"elements":["property"]},"single_line_after_imports":true,"spaces_inside_parentheses":true,"statement_indentation":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"encoding":true,"full_opening_tag":true},"hashes":{"src\/Exception\/RuleException.php":"0f48d4b0d809e8eab61416c2db16a7d8","src\/FileInfo.php":"92199a788c035eee744222d874975264","src\/RuleInterface.php":"510ec2377e44bc9cd60734290b78a182","src\/Rule\/Extension.php":"91951f96a6b9a0880fb555c0a16cec54","src\/Rule\/MediaType.php":"2a1e550418cdc2041a8cdbace9ff6375","src\/Rule\/Size.php":"80e2e7c2888a6e79b6cf71ab8e6c80e6","tests\/FileInfoTest.php":"75ad22380821d20a861e036706f70333","tests\/UploadProcessingTest.php":"6fda40150d71be7fe67c61d154f74233","tests\/Rule\/SizeTest.php":"67f50eca6d49ff1969f14adee342f6f9","tests\/Rule\/ExtensionTest.php":"5f5adc4bbe15b6c2ce19320df3c377c9","tests\/Rule\/MediaTypeTest.php":"ac581940014eb72cb2f6bd75ee28104f","src\/Event\/BeforeUploadEvent.php":"4b727d6ca152ff45965753f4184a3574","src\/Event\/AfterUploadEvent.php":"3192076007a8a74f9b86e978b8944292","src\/Event\/BeforeValidationEvent.php":"05b3f4f36012e9bfee9b807be9b34531","src\/Event\/UploadErrorEvent.php":"76a178f671c0a2c20b646b6fef7dd106","src\/Event\/AbstractUploadEvent.php":"c923ca05323acb119f453de57576943e","tests\/UploadProcessingEventTest.php":"5b3284c8e9e09f1088f9ccb877cca30d","src\/UploadProcessing.php":"39b35f1fe6323fc5c681cb838b4043f8"}} \ No newline at end of file diff --git a/tests/UploadProcessingEventTest.php b/tests/UploadProcessingEventTest.php index 38f72fe..bc34f6f 100644 --- a/tests/UploadProcessingEventTest.php +++ b/tests/UploadProcessingEventTest.php @@ -1,4 +1,5 @@ createUploadedFile(); - $dispatcher = new class implements EventDispatcherInterface { + $dispatcher = new class () implements EventDispatcherInterface { public array $dispatchedEvents = []; public function dispatch(object $event): object @@ -174,7 +175,7 @@ private function createUploadedFile(?string $clientFilename = null, ?string $med public function testEventPropagation(): void { - $event = new class extends AbstractUploadEvent {}; + $event = new class () extends AbstractUploadEvent {}; $this->assertFalse($event->isPropagationStopped()); $event->stopPropagation(); $this->assertTrue($event->isPropagationStopped()); @@ -183,7 +184,7 @@ public function testEventPropagation(): void public function testEventPropagationStopping(): void { - $dispatcher = new class implements EventDispatcherInterface { + $dispatcher = new class () implements EventDispatcherInterface { public array $dispatchedEvents = []; public function dispatch(object $event): object From 1c6e811cae7af28d9ed47a5257a5f4892420523e Mon Sep 17 00:00:00 2001 From: enjoys Date: Sat, 28 Jun 2025 12:01:28 +0300 Subject: [PATCH 13/15] remove .php-cs-fixer.cache --- .php-cs-fixer.cache | 1 - src/UploadProcessing.php | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 .php-cs-fixer.cache diff --git a/.php-cs-fixer.cache b/.php-cs-fixer.cache deleted file mode 100644 index 45583a5..0000000 --- a/.php-cs-fixer.cache +++ /dev/null @@ -1 +0,0 @@ -{"php":"8.2.19","version":"3.75.0","indent":" ","lineEnding":"\n","rules":{"binary_operator_spaces":{"default":"at_least_single_space"},"blank_line_after_opening_tag":true,"blank_line_between_import_groups":true,"blank_lines_before_namespace":true,"braces_position":{"allow_single_line_empty_anonymous_classes":true},"class_definition":{"inline_constructor_arguments":false,"space_before_parenthesis":true},"compact_nullable_type_declaration":true,"declare_equal_normalize":true,"lowercase_cast":true,"lowercase_static_reference":true,"new_with_parentheses":true,"no_blank_lines_after_class_opening":true,"no_extra_blank_lines":{"tokens":["use"]},"no_leading_import_slash":true,"no_whitespace_in_blank_line":true,"ordered_class_elements":{"order":["use_trait"]},"ordered_imports":{"imports_order":["class","function","const"],"sort_algorithm":"none"},"return_type_declaration":true,"short_scalar_cast":true,"single_import_per_statement":{"group_to_single_imports":false},"single_space_around_construct":{"constructs_followed_by_a_single_space":["abstract","as","case","catch","class","const_import","do","else","elseif","final","finally","for","foreach","function","function_import","if","insteadof","interface","namespace","new","private","protected","public","static","switch","trait","try","use","use_lambda","while"],"constructs_preceded_by_a_single_space":["as","else","elseif","use_lambda"]},"single_trait_insert_per_statement":true,"ternary_operator_spaces":true,"unary_operator_spaces":{"only_dec_inc":true},"visibility_required":true,"blank_line_after_namespace":true,"constant_case":true,"control_structure_braces":true,"control_structure_continuation_position":true,"elseif":true,"function_declaration":true,"indentation_type":true,"line_ending":true,"lowercase_keywords":true,"method_argument_space":{"attribute_placement":"ignore","on_multiline":"ensure_fully_multiline"},"no_break_comment":true,"no_closing_tag":true,"no_multiple_statements_per_line":true,"no_space_around_double_colon":true,"no_spaces_after_function_name":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":{"elements":["property"]},"single_line_after_imports":true,"spaces_inside_parentheses":true,"statement_indentation":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"encoding":true,"full_opening_tag":true},"hashes":{"src\/Exception\/RuleException.php":"0f48d4b0d809e8eab61416c2db16a7d8","src\/FileInfo.php":"92199a788c035eee744222d874975264","src\/RuleInterface.php":"510ec2377e44bc9cd60734290b78a182","src\/Rule\/Extension.php":"91951f96a6b9a0880fb555c0a16cec54","src\/Rule\/MediaType.php":"2a1e550418cdc2041a8cdbace9ff6375","src\/Rule\/Size.php":"80e2e7c2888a6e79b6cf71ab8e6c80e6","tests\/FileInfoTest.php":"75ad22380821d20a861e036706f70333","tests\/UploadProcessingTest.php":"6fda40150d71be7fe67c61d154f74233","tests\/Rule\/SizeTest.php":"67f50eca6d49ff1969f14adee342f6f9","tests\/Rule\/ExtensionTest.php":"5f5adc4bbe15b6c2ce19320df3c377c9","tests\/Rule\/MediaTypeTest.php":"ac581940014eb72cb2f6bd75ee28104f","src\/Event\/BeforeUploadEvent.php":"4b727d6ca152ff45965753f4184a3574","src\/Event\/AfterUploadEvent.php":"3192076007a8a74f9b86e978b8944292","src\/Event\/BeforeValidationEvent.php":"05b3f4f36012e9bfee9b807be9b34531","src\/Event\/UploadErrorEvent.php":"76a178f671c0a2c20b646b6fef7dd106","src\/Event\/AbstractUploadEvent.php":"c923ca05323acb119f453de57576943e","tests\/UploadProcessingEventTest.php":"5b3284c8e9e09f1088f9ccb877cca30d","src\/UploadProcessing.php":"39b35f1fe6323fc5c681cb838b4043f8"}} \ No newline at end of file diff --git a/src/UploadProcessing.php b/src/UploadProcessing.php index f6be3b8..aa09139 100644 --- a/src/UploadProcessing.php +++ b/src/UploadProcessing.php @@ -88,6 +88,7 @@ private function validate(): void } } + /** * Sets the filename for the uploaded file * Automatically adds an extension if it is not specified From b953f401a88f844b4bb0a833b02046d552bf27f0 Mon Sep 17 00:00:00 2001 From: enjoys Date: Sat, 28 Jun 2025 12:02:21 +0300 Subject: [PATCH 14/15] test... --- src/UploadProcessing.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/UploadProcessing.php b/src/UploadProcessing.php index aa09139..24ef810 100644 --- a/src/UploadProcessing.php +++ b/src/UploadProcessing.php @@ -2,6 +2,7 @@ declare(strict_types=1); + namespace Enjoys\Upload; use Enjoys\Upload\Event\AfterUploadEvent; @@ -88,7 +89,6 @@ private function validate(): void } } - /** * Sets the filename for the uploaded file * Automatically adds an extension if it is not specified From df74a809868f60e0d4aa97959f5ee58098999606 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sat, 28 Jun 2025 09:02:41 +0000 Subject: [PATCH 15/15] Apply PHP-CS-Fixer fixes [skip ci] --- src/UploadProcessing.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/UploadProcessing.php b/src/UploadProcessing.php index 24ef810..f6be3b8 100644 --- a/src/UploadProcessing.php +++ b/src/UploadProcessing.php @@ -2,7 +2,6 @@ declare(strict_types=1); - namespace Enjoys\Upload; use Enjoys\Upload\Event\AfterUploadEvent;