<?php /** * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; under version 2 * of the License (non-upgradable). * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (c) 2017 (original work) Open Assessment Technologies SA; * */ namespace oat\taoDelivery\model\execution; use common_exception_NotFound; use oat\oatbox\event\Event; use oat\oatbox\event\EventManager; use oat\oatbox\log\LoggerAwareTrait; use oat\oatbox\service\ConfigurableService; use oat\oatbox\session\SessionService; use oat\oatbox\user\User; use oat\taoDelivery\models\classes\execution\event\DeliveryExecutionCreated; use oat\taoDelivery\models\classes\execution\event\DeliveryExecutionReactivated; use oat\taoDelivery\models\classes\execution\event\DeliveryExecutionState as DeliveryExecutionStateEvent; /** * Class AbstractStateService * @package oat\taoDelivery * @author Aleh Hutnikau, <hutnikau@1pt.com> */ abstract class AbstractStateService extends ConfigurableService implements StateServiceInterface { use LoggerAwareTrait; public const OPTION_REACTIVABLE_STATES = 'reactivableStates'; private const DEFAULT_REACTIVABLE_STATES = [ DeliveryExecutionInterface::STATE_TERMINATED, ]; private const INTERACTIVE_STATES = [ DeliveryExecutionInterface::STATE_ACTIVE, DeliveryExecutionInterface::STATE_PAUSED, ]; /** * Legacy function to ensure all calls to setState use * the correct transition instead * * @param DeliveryExecution $deliveryExecution * @param string $state * * @return bool */ abstract public function legacyTransition(DeliveryExecution $deliveryExecution, $state); /** * Get the status new delivery executions should be started with * * @param string $deliveryId * @param User $user * * @return string */ abstract public function getInitialStatus($deliveryId, User $user); /** * @inheritDoc */ public function createDeliveryExecution($deliveryId, User $user, $label) { $status = $this->getInitialStatus($deliveryId, $user); $deliveryExecution = $this->getStorageEngine()->spawnDeliveryExecution($label, $deliveryId, $user->getIdentifier(), $status); // trigger event $event = new DeliveryExecutionCreated($deliveryExecution, $user); $this->getEventManager()->trigger($event); return $deliveryExecution; } /** * @inheritDoc */ public function reactivateExecution(DeliveryExecution $deliveryExecution, $reason = null) { $executionState = $deliveryExecution->getState()->getUri(); $result = false; if (in_array($executionState, $this->getReactivableStates(), true)) { $this->setState($deliveryExecution, DeliveryExecution::STATE_PAUSED, $reason); $result = true; } return $result; } /** * @param DeliveryExecution $deliveryExecution * @param string $state * @param string|array|null $reason * * @return bool * * @throws common_exception_NotFound */ protected function setState(DeliveryExecution $deliveryExecution, string $state, $reason = null): bool { $previousState = $deliveryExecution->getState()->getUri(); if ($previousState === $state) { $this->logWarning('Delivery execution ' . $deliveryExecution->getIdentifier() . ' already in state ' . $state); return false; } $result = $deliveryExecution->getImplementation()->setState($state); $this->emitEvent(new DeliveryExecutionStateEvent($deliveryExecution, $state, $previousState)); $this->logDebug(sprintf('DeliveryExecutionState from %s to %s triggered', $previousState, $state)); if (!$this->isStateInteractive($previousState) && $this->isStateInteractive($state)) { $this->emitEvent( new DeliveryExecutionReactivated( $deliveryExecution, $this->getSessionService()->getCurrentUser(), $reason ) ); } return $result; } protected function getStorageEngine(): DeliveryExecutionService { /** @noinspection PhpIncompatibleReturnTypeInspection */ return $this->getServiceLocator()->get(DeliveryExecutionService::SERVICE_ID); } private function getSessionService(): SessionService { /** @noinspection PhpIncompatibleReturnTypeInspection */ return $this->getServiceLocator()->get(SessionService::SERVICE_ID); } private function getEventManager(): EventManager { /** @noinspection PhpIncompatibleReturnTypeInspection */ return $this->getServiceLocator()->get(EventManager::SERVICE_ID); } private function emitEvent(Event $event): void { $this->getEventManager()->trigger($event); } private function getReactivableStates(): array { if (!$this->hasOption(self::OPTION_REACTIVABLE_STATES)) { return self::DEFAULT_REACTIVABLE_STATES; } return $this->getOption(self::OPTION_REACTIVABLE_STATES); } private function isStateInteractive(string $state): bool { return in_array($state, self::INTERACTIVE_STATES, true); } }