Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>tags/v21.0.0beta1
@@ -77,6 +77,7 @@ return array( | |||
'OCP\\AppFramework\\QueryException' => $baseDir . '/lib/public/AppFramework/QueryException.php', | |||
'OCP\\AppFramework\\Services\\IAppConfig' => $baseDir . '/lib/public/AppFramework/Services/IAppConfig.php', | |||
'OCP\\AppFramework\\Services\\IInitialState' => $baseDir . '/lib/public/AppFramework/Services/IInitialState.php', | |||
'OCP\\AppFramework\\Services\\InitialStateProvider' => $baseDir . '/lib/public/AppFramework/Services/InitialStateProvider.php', | |||
'OCP\\AppFramework\\Utility\\IControllerMethodReflector' => $baseDir . '/lib/public/AppFramework/Utility/IControllerMethodReflector.php', | |||
'OCP\\AppFramework\\Utility\\ITimeFactory' => $baseDir . '/lib/public/AppFramework/Utility/ITimeFactory.php', | |||
'OCP\\App\\AppPathNotFoundException' => $baseDir . '/lib/public/App/AppPathNotFoundException.php', |
@@ -106,6 +106,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c | |||
'OCP\\AppFramework\\QueryException' => __DIR__ . '/../../..' . '/lib/public/AppFramework/QueryException.php', | |||
'OCP\\AppFramework\\Services\\IAppConfig' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Services/IAppConfig.php', | |||
'OCP\\AppFramework\\Services\\IInitialState' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Services/IInitialState.php', | |||
'OCP\\AppFramework\\Services\\InitialStateProvider' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Services/InitialStateProvider.php', | |||
'OCP\\AppFramework\\Utility\\IControllerMethodReflector' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Utility/IControllerMethodReflector.php', | |||
'OCP\\AppFramework\\Utility\\ITimeFactory' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Utility/ITimeFactory.php', | |||
'OCP\\App\\AppPathNotFoundException' => __DIR__ . '/../../..' . '/lib/public/App/AppPathNotFoundException.php', |
@@ -69,6 +69,9 @@ class RegistrationContext { | |||
/** @var array[] */ | |||
private $alternativeLogins = []; | |||
/** @var array[] */ | |||
private $initialStates = []; | |||
/** @var ILogger */ | |||
private $logger; | |||
@@ -164,6 +167,13 @@ class RegistrationContext { | |||
$class | |||
); | |||
} | |||
public function registerInitialStateProvider(string $class): void { | |||
$this->context->registerInitialState( | |||
$this->appId, | |||
$class | |||
); | |||
} | |||
}; | |||
} | |||
@@ -243,6 +253,13 @@ class RegistrationContext { | |||
]; | |||
} | |||
public function registerInitialState(string $appId, string $class): void { | |||
$this->initialStates[] = [ | |||
'appId' => $appId, | |||
'class' => $class, | |||
]; | |||
} | |||
/** | |||
* @param App[] $apps | |||
*/ | |||
@@ -413,4 +430,11 @@ class RegistrationContext { | |||
public function getAlternativeLogins(): array { | |||
return $this->alternativeLogins; | |||
} | |||
/** | |||
* @erturn array[] | |||
*/ | |||
public function getInitialStates(): array { | |||
return $this->initialStates; | |||
} | |||
} |
@@ -28,8 +28,12 @@ declare(strict_types=1); | |||
namespace OC; | |||
use Closure; | |||
use OC\AppFramework\Bootstrap\Coordinator; | |||
use OCP\AppFramework\QueryException; | |||
use OCP\AppFramework\Services\InitialStateProvider; | |||
use OCP\IInitialStateService; | |||
use OCP\ILogger; | |||
use OCP\IServerContainer; | |||
class InitialStateService implements IInitialStateService { | |||
@@ -42,8 +46,16 @@ class InitialStateService implements IInitialStateService { | |||
/** @var Closure[][] */ | |||
private $lazyStates = []; | |||
public function __construct(ILogger $logger) { | |||
/** @var Coordinator */ | |||
private $bootstrapCoordinator; | |||
/** @var IServerContainer */ | |||
private $container; | |||
public function __construct(ILogger $logger, Coordinator $bootstrapCoordinator, IServerContainer $container) { | |||
$this->logger = $logger; | |||
$this->bootstrapCoordinator = $bootstrapCoordinator; | |||
$this->container = $container; | |||
} | |||
public function provideInitialState(string $appName, string $key, $data): void { | |||
@@ -88,8 +100,45 @@ class InitialStateService implements IInitialStateService { | |||
$this->lazyStates = []; | |||
} | |||
/** | |||
* Load the lazy states via the IBootstrap mechanism | |||
*/ | |||
private function loadLazyStates(): void { | |||
$context = $this->bootstrapCoordinator->getRegistrationContext(); | |||
if ($context === null) { | |||
// To early, nothing to do yet | |||
return; | |||
} | |||
$initialStates = $context->getInitialStates(); | |||
foreach ($initialStates as $initialState) { | |||
try { | |||
$provider = $this->container->query($initialState['class']); | |||
} catch (QueryException $e) { | |||
// Log an continue. We can be fault tolerant here. | |||
$this->logger->logException($e, [ | |||
'message' => 'Could not load initial state provider dynamically: ' . $e->getMessage(), | |||
'level' => ILogger::ERROR, | |||
'app' => $initialState['appId'], | |||
]); | |||
continue; | |||
} | |||
if (!($provider instanceof InitialStateProvider)) { | |||
// Log an continue. We can be fault tolerant here. | |||
$this->logger->error('Initial state provider is not an InitialStateProvider instance: ' . $initialState['class'], [ | |||
'app' => $initialState['appId'], | |||
]); | |||
} | |||
$this->provideInitialState($initialState['appId'], $provider->getKey(), $provider); | |||
} | |||
} | |||
public function getInitialStates(): array { | |||
$this->invokeLazyStateCallbacks(); | |||
$this->loadLazyStates(); | |||
$appStates = []; | |||
foreach ($this->states as $app => $states) { |
@@ -155,4 +155,17 @@ interface IRegistrationContext { | |||
* @since 20.0.0 | |||
*/ | |||
public function registerAlternativeLogin(string $class): void; | |||
/** | |||
* Register an initialstate provider | |||
* | |||
* It is allowed to register more than one provider per app. | |||
* | |||
* @param string $class | |||
* | |||
* @return void | |||
* | |||
* @since 21.0.0 | |||
*/ | |||
public function registerInitialStateProvider(string $class): void; | |||
} |
@@ -0,0 +1,49 @@ | |||
<?php | |||
declare(strict_types=1); | |||
/** | |||
* @copyright Copyright (c) 2020, Roeland Jago Douma <roeland@famdouma.nl> | |||
* | |||
* @author Roeland Jago Douma <roeland@famdouma.nl> | |||
* | |||
* @license GNU AGPL version 3 or any later version | |||
* | |||
* This program is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Affero General Public License as | |||
* published by the Free Software Foundation, either version 3 of the | |||
* License, or (at your option) any later version. | |||
* | |||
* 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 Affero General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public License | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OCP\AppFramework\Services; | |||
/** | |||
* @since 21.0.0 | |||
*/ | |||
abstract class InitialStateProvider implements \JsonSerializable { | |||
/** | |||
* @since 21.0.0 | |||
*/ | |||
abstract public function getKey(): string; | |||
/** | |||
* @since 21.0.0 | |||
*/ | |||
abstract public function getData(); | |||
/** | |||
* @since 21.0.0 | |||
*/ | |||
final public function jsonSerialize() { | |||
return $this->getData(); | |||
} | |||
} |
@@ -43,6 +43,8 @@ interface IInitialStateService { | |||
* @param string $appName | |||
* @param string $key | |||
* @param bool|int|float|string|array|\JsonSerializable $data | |||
* | |||
* @deprecated 21 Use OCP\AppFramework\Services\IInitialState or OCP\AppFramework\Services\InitialStateProvider | |||
*/ | |||
public function provideInitialState(string $appName, string $key, $data): void; | |||
@@ -58,6 +60,8 @@ interface IInitialStateService { | |||
* @param string $appName | |||
* @param string $key | |||
* @param Closure $closure returns a primitive or an object that implements JsonSerializable | |||
* | |||
* @deprecated 21 Use OCP\AppFramework\Services\IInitialState or OCP\AppFramework\Services\InitialStateProvider | |||
*/ | |||
public function provideLazyInitialState(string $appName, string $key, Closure $closure): void; | |||
} |
@@ -25,6 +25,8 @@ declare(strict_types=1); | |||
namespace Test; | |||
use OC\AppFramework\Bootstrap\Coordinator; | |||
use OCP\IServerContainer; | |||
use function json_encode; | |||
use JsonSerializable; | |||
use OC\InitialStateService; | |||
@@ -40,7 +42,9 @@ class InitialStateServiceTest extends TestCase { | |||
parent::setUp(); | |||
$this->service = new InitialStateService( | |||
$this->createMock(ILogger::class) | |||
$this->createMock(ILogger::class), | |||
$this->createMock(Coordinator::class), | |||
$this->createMock(IServerContainer::class) | |||
); | |||
} | |||