From c0814c5ef453ad0c75d8086ead3855357e64e580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20W=C3=B3js?= Date: Thu, 11 Jan 2024 11:46:25 +0100 Subject: [PATCH] IBX-7287: Introduced Autosave API (#1082) --- .../Resources/config/services/autosave.yaml | 5 ++ .../Autosave/AutosaveServiceInterface.php | 26 ++++++++ src/lib/Autosave/AutosaveService.php | 49 ++++++++++++++ .../ContentProxyCreateDraftListener.php | 27 +++----- .../Processor/Content/AutosaveProcessor.php | 11 +++- src/lib/UI/Config/Provider/Autosave.php | 20 ++---- src/lib/UserSetting/Autosave.php | 2 + src/lib/UserSetting/AutosaveInterval.php | 2 + tests/lib/Autosave/AutosaveServiceTest.php | 64 +++++++++++++++++++ .../ContentProxyCreateDraftListenerTest.php | 56 ++++------------ 10 files changed, 186 insertions(+), 76 deletions(-) create mode 100644 src/contracts/Autosave/AutosaveServiceInterface.php create mode 100644 src/lib/Autosave/AutosaveService.php create mode 100644 tests/lib/Autosave/AutosaveServiceTest.php diff --git a/src/bundle/Resources/config/services/autosave.yaml b/src/bundle/Resources/config/services/autosave.yaml index a03d200447..4b414058b0 100644 --- a/src/bundle/Resources/config/services/autosave.yaml +++ b/src/bundle/Resources/config/services/autosave.yaml @@ -4,6 +4,11 @@ services: autowire: true public: false + Ibexa\AdminUi\Autosave\AutosaveService: ~ + + Ibexa\Contracts\AdminUi\Autosave\AutosaveServiceInterface: + alias: Ibexa\AdminUi\Autosave\AutosaveService + Ibexa\AdminUi\EventListener\ContentProxyCreateDraftListener: ~ Ibexa\AdminUi\Form\Processor\Content\AutosaveProcessor: diff --git a/src/contracts/Autosave/AutosaveServiceInterface.php b/src/contracts/Autosave/AutosaveServiceInterface.php new file mode 100644 index 0000000000..c78cec9743 --- /dev/null +++ b/src/contracts/Autosave/AutosaveServiceInterface.php @@ -0,0 +1,26 @@ +userSettingService = $userSettingService; + } + + public function isEnabled(): bool + { + return $this->userSettingService->getUserSetting(Autosave::IDENTIFIER)->value === Autosave::ENABLED_OPTION; + } + + /** + * Returns autosave interval in milliseconds. + */ + public function getInterval(): int + { + return (int)$this->userSettingService->getUserSetting(AutosaveInterval::IDENTIFIER)->value * 1000; + } + + public function isInProgress(): bool + { + return $this->inProgress; + } + + public function setInProgress(bool $isInProgress): void + { + $this->inProgress = $isInProgress; + } +} diff --git a/src/lib/EventListener/ContentProxyCreateDraftListener.php b/src/lib/EventListener/ContentProxyCreateDraftListener.php index a429942c37..1f3d3f4f54 100644 --- a/src/lib/EventListener/ContentProxyCreateDraftListener.php +++ b/src/lib/EventListener/ContentProxyCreateDraftListener.php @@ -8,41 +8,36 @@ namespace Ibexa\AdminUi\EventListener; -use Ibexa\AdminUi\UserSetting\Autosave as AutosaveSetting; +use Ibexa\Contracts\AdminUi\Autosave\AutosaveServiceInterface; use Ibexa\Contracts\AdminUi\Event\ContentProxyCreateEvent; use Ibexa\Contracts\AdminUi\Event\ContentProxyTranslateEvent; use Ibexa\Contracts\Core\Repository\ContentService; use Ibexa\Contracts\Core\Repository\LocationService; use Ibexa\Contracts\Core\Repository\Values\Content\Content; use Ibexa\Contracts\Core\Repository\Values\Content\Field; -use Ibexa\User\UserSetting\UserSettingService; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\Routing\RouterInterface; class ContentProxyCreateDraftListener implements EventSubscriberInterface { - /** @var \Ibexa\Contracts\Core\Repository\ContentService */ - private $contentService; + private ContentService $contentService; - /** @var \Ibexa\Contracts\Core\Repository\LocationService */ - private $locationService; + private LocationService $locationService; - /** @var \Ibexa\User\UserSetting\UserSettingService */ - private $userSettingService; + private AutosaveServiceInterface $autosaveService; - /** @var \Symfony\Component\Routing\RouterInterface */ - private $router; + private RouterInterface $router; public function __construct( ContentService $contentService, LocationService $locationService, - UserSettingService $userSettingService, + AutosaveServiceInterface $autosaveService, RouterInterface $router ) { $this->contentService = $contentService; $this->locationService = $locationService; - $this->userSettingService = $userSettingService; + $this->autosaveService = $autosaveService; $this->router = $router; } @@ -56,9 +51,7 @@ public static function getSubscribedEvents(): array public function create(ContentProxyCreateEvent $event): void { - $isAutosaveEnabled = $this->userSettingService->getUserSetting('autosave')->value === AutosaveSetting::ENABLED_OPTION; - - if (!$isAutosaveEnabled) { + if (!$this->autosaveService->isEnabled()) { return; } @@ -103,9 +96,7 @@ public function create(ContentProxyCreateEvent $event): void public function translate(ContentProxyTranslateEvent $event): void { - $isAutosaveEnabled = $this->userSettingService->getUserSetting('autosave')->value === AutosaveSetting::ENABLED_OPTION; - - if (!$isAutosaveEnabled) { + if (!$this->autosaveService->isEnabled()) { return; } diff --git a/src/lib/Form/Processor/Content/AutosaveProcessor.php b/src/lib/Form/Processor/Content/AutosaveProcessor.php index 44ddf029cf..0431230db8 100644 --- a/src/lib/Form/Processor/Content/AutosaveProcessor.php +++ b/src/lib/Form/Processor/Content/AutosaveProcessor.php @@ -10,6 +10,7 @@ use Ibexa\ContentForms\Event\FormActionEvent; use Ibexa\ContentForms\Form\Processor\ContentFormProcessor; +use Ibexa\Contracts\AdminUi\Autosave\AutosaveServiceInterface; use Ibexa\Contracts\AdminUi\Event\AutosaveEvents; use Ibexa\Contracts\Core\Repository\Exceptions\Exception as APIException; use Symfony\Component\EventDispatcher\EventSubscriberInterface; @@ -17,12 +18,15 @@ class AutosaveProcessor implements EventSubscriberInterface { - /** @var \Ibexa\ContentForms\Form\Processor\ContentFormProcessor */ - private $innerContentFormProcessor; + private AutosaveServiceInterface $autosaveService; + + private ContentFormProcessor $innerContentFormProcessor; public function __construct( + AutosaveServiceInterface $autosaveService, ContentFormProcessor $innerContentFormProcessor ) { + $this->autosaveService = $autosaveService; $this->innerContentFormProcessor = $innerContentFormProcessor; } @@ -36,10 +40,13 @@ public static function getSubscribedEvents(): array public function processAutosave(FormActionEvent $event): void { try { + $this->autosaveService->setInProgress(true); $this->innerContentFormProcessor->processSaveDraft($event); $statusCode = Response::HTTP_OK; } catch (APIException $exception) { $statusCode = Response::HTTP_BAD_REQUEST; + } finally { + $this->autosaveService->setInProgress(false); } $event->setResponse( diff --git a/src/lib/UI/Config/Provider/Autosave.php b/src/lib/UI/Config/Provider/Autosave.php index b7b4fd3db5..7977168b51 100644 --- a/src/lib/UI/Config/Provider/Autosave.php +++ b/src/lib/UI/Config/Provider/Autosave.php @@ -8,29 +8,23 @@ namespace Ibexa\AdminUi\UI\Config\Provider; -use Ibexa\AdminUi\UserSetting\Autosave as AutosaveSetting; +use Ibexa\Contracts\AdminUi\Autosave\AutosaveServiceInterface; use Ibexa\Contracts\AdminUi\UI\Config\ProviderInterface; -use Ibexa\User\UserSetting\UserSettingService; class Autosave implements ProviderInterface { - /** @var \Ibexa\User\UserSetting\UserSettingService */ - private $userSettingService; + private AutosaveServiceInterface $autosaveService; - public function __construct( - UserSettingService $userSettingService - ) { - $this->userSettingService = $userSettingService; + public function __construct(AutosaveServiceInterface $autosaveService) + { + $this->autosaveService = $autosaveService; } public function getConfig(): array { - $isEnabled = $this->userSettingService->getUserSetting('autosave')->value === AutosaveSetting::ENABLED_OPTION; - $interval = (int)$this->userSettingService->getUserSetting('autosave_interval')->value * 1000; - return [ - 'enabled' => $isEnabled, - 'interval' => $interval, + 'enabled' => $this->autosaveService->isEnabled(), + 'interval' => $this->autosaveService->getInterval(), ]; } } diff --git a/src/lib/UserSetting/Autosave.php b/src/lib/UserSetting/Autosave.php index 060bee38cf..7b44a9ed68 100644 --- a/src/lib/UserSetting/Autosave.php +++ b/src/lib/UserSetting/Autosave.php @@ -19,6 +19,8 @@ class Autosave implements ValueDefinitionInterface, FormMapperInterface { + public const IDENTIFIER = 'autosave'; + public const ENABLED_OPTION = 'enabled'; public const DISABLED_OPTION = 'disabled'; diff --git a/src/lib/UserSetting/AutosaveInterval.php b/src/lib/UserSetting/AutosaveInterval.php index 6b9412284a..839c8d7de0 100644 --- a/src/lib/UserSetting/AutosaveInterval.php +++ b/src/lib/UserSetting/AutosaveInterval.php @@ -18,6 +18,8 @@ class AutosaveInterval implements ValueDefinitionInterface, FormMapperInterface { + public const IDENTIFIER = 'autosave_interval'; + /** @var \Symfony\Contracts\Translation\TranslatorInterface */ private $translator; diff --git a/tests/lib/Autosave/AutosaveServiceTest.php b/tests/lib/Autosave/AutosaveServiceTest.php new file mode 100644 index 0000000000..6c7a997901 --- /dev/null +++ b/tests/lib/Autosave/AutosaveServiceTest.php @@ -0,0 +1,64 @@ +userSettingService = $this->createMock(UserSettingService::class); + $this->autosaveService = new AutosaveService($this->userSettingService); + } + + public function testIsEnabled(): void + { + $this->userSettingService + ->method('getUserSetting') + ->with(Autosave::IDENTIFIER) + ->willReturn($this->createUserSettingWithValue(Autosave::ENABLED_OPTION)); + + self::assertTrue($this->autosaveService->isEnabled()); + } + + public function testGetInterval(): void + { + $this->userSettingService + ->method('getUserSetting') + ->with(AutosaveInterval::IDENTIFIER) + ->willReturn($this->createUserSettingWithValue('30')); + + self::assertEquals(30000, $this->autosaveService->getInterval()); + } + + public function testIsInProgress(): void + { + self::assertFalse($this->autosaveService->isInProgress()); + $this->autosaveService->setInProgress(true); + self::assertTrue($this->autosaveService->isInProgress()); + } + + private function createUserSettingWithValue(string $value): UserSetting + { + return new UserSetting([ + 'value' => $value, + ]); + } +} diff --git a/tests/lib/EventListener/ContentProxyCreateDraftListenerTest.php b/tests/lib/EventListener/ContentProxyCreateDraftListenerTest.php index 84af788fc8..6fb7743c02 100644 --- a/tests/lib/EventListener/ContentProxyCreateDraftListenerTest.php +++ b/tests/lib/EventListener/ContentProxyCreateDraftListenerTest.php @@ -10,7 +10,7 @@ use Ibexa\AdminUi\Event\Options; use Ibexa\AdminUi\EventListener\ContentProxyCreateDraftListener; -use Ibexa\AdminUi\UserSetting\Autosave; +use Ibexa\Contracts\AdminUi\Autosave\AutosaveServiceInterface; use Ibexa\Contracts\AdminUi\Event\ContentProxyCreateEvent; use Ibexa\Contracts\AdminUi\Event\ContentProxyTranslateEvent; use Ibexa\Contracts\Core\FieldType\Value; @@ -22,8 +22,6 @@ use Ibexa\Core\Repository\Values\ContentType\ContentType; use Ibexa\Core\Repository\Values\ContentType\FieldDefinition; use Ibexa\Core\Repository\Values\ContentType\FieldDefinitionCollection; -use Ibexa\User\UserSetting\UserSetting; -use Ibexa\User\UserSetting\UserSettingService; use PHPUnit\Framework\TestCase; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\HttpFoundation\RedirectResponse; @@ -33,15 +31,8 @@ final class ContentProxyCreateDraftListenerTest extends TestCase { public function testCreateContentAutosaveEnabled(): void { - $userSettingService = $this->createMock(UserSettingService::class); - $userSettingService - ->method('getUserSetting') - ->with('autosave') - ->willReturn( - new UserSetting([ - 'value' => Autosave::ENABLED_OPTION, - ]) - ); + $autosaveService = $this->createMock(AutosaveServiceInterface::class); + $autosaveService->method('isEnabled')->willReturn(true); $contentService = $this->createMock(ContentService::class); $contentService @@ -69,7 +60,7 @@ public function testCreateContentAutosaveEnabled(): void new ContentProxyCreateDraftListener( $contentService, $this->createMock(LocationService::class), - $userSettingService, + $autosaveService, $router ) ); @@ -85,15 +76,8 @@ public function testCreateContentAutosaveEnabled(): void public function testCreateContentOnTheFlyAutosaveEnabled(): void { - $userSettingService = $this->createMock(UserSettingService::class); - $userSettingService - ->method('getUserSetting') - ->with('autosave') - ->willReturn( - new UserSetting([ - 'value' => Autosave::ENABLED_OPTION, - ]) - ); + $autosaveService = $this->createMock(AutosaveServiceInterface::class); + $autosaveService->method('isEnabled')->willReturn(true); $contentInfo = $this->createMock(ContentInfo::class); @@ -138,7 +122,7 @@ public function testCreateContentOnTheFlyAutosaveEnabled(): void new ContentProxyCreateDraftListener( $contentService, $this->createMock(LocationService::class), - $userSettingService, + $autosaveService, $router ) ); @@ -154,15 +138,8 @@ public function testCreateContentOnTheFlyAutosaveEnabled(): void public function testTranslateContentAutosaveEnabled(): void { - $userSettingService = $this->createMock(UserSettingService::class); - $userSettingService - ->method('getUserSetting') - ->with('autosave') - ->willReturn( - new UserSetting([ - 'value' => Autosave::ENABLED_OPTION, - ]) - ); + $autosaveService = $this->createMock(AutosaveServiceInterface::class); + $autosaveService->method('isEnabled')->willReturn(true); $contentType = $this->getContentType([ $this->getFieldDefinition('field_a', true), @@ -222,7 +199,7 @@ public function testTranslateContentAutosaveEnabled(): void new ContentProxyCreateDraftListener( $contentService, $this->createMock(LocationService::class), - $userSettingService, + $autosaveService, $router ) ); @@ -234,15 +211,8 @@ public function testTranslateContentAutosaveEnabled(): void public function testAutosaveDisabled(): void { - $userSettingService = $this->createMock(UserSettingService::class); - $userSettingService - ->method('getUserSetting') - ->with('autosave') - ->willReturn( - new UserSetting([ - 'value' => Autosave::DISABLED_OPTION, - ]) - ); + $autosaveService = $this->createMock(AutosaveServiceInterface::class); + $autosaveService->method('isEnabled')->willReturn(true); $contentService = $this->createMock(ContentService::class); $contentService @@ -275,7 +245,7 @@ public function testAutosaveDisabled(): void new ContentProxyCreateDraftListener( $contentService, $this->createMock(LocationService::class), - $userSettingService, + $autosaveService, $this->createMock(RouterInterface::class) ) );