-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rework PluginContainer to fix singleton instance problems with multip…
…le plugins
- Loading branch information
Showing
7 changed files
with
279 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
/* | ||
* This file is part of the ilias-plugin-utils Library for ILIAS. | ||
* | ||
* (c) Thomas Joußen <[email protected]> | ||
* | ||
* This source file is subject to the GPL-3.0 license that is bundled | ||
* with this source code in the file LICENSE. | ||
*/ | ||
|
||
namespace Thojou\Ilias\Plugin\Utils\DI; | ||
|
||
use Exception; | ||
use Psr\Container\ContainerExceptionInterface; | ||
|
||
/** | ||
* PluginContainerException | ||
* | ||
* This class represents an exception that is thrown when a container error occurs. | ||
* | ||
* @author Thomas Joußen <[email protected]> | ||
* @see https://www.php-fig.org/psr/psr-11/#32-psrcontainercontainerexceptioninterface | ||
*/ | ||
class PluginContainerException extends \RuntimeException implements ContainerExceptionInterface | ||
{ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
/* | ||
* This file is part of the ilias-plugin-utils Library for ILIAS. | ||
* | ||
* (c) Thomas Joußen <[email protected]> | ||
* | ||
* This source file is subject to the GPL-3.0 license that is bundled | ||
* with this source code in the file LICENSE. | ||
*/ | ||
|
||
namespace Thojou\Ilias\Plugin\Utils\DI; | ||
|
||
use ILIAS\DI\Container; | ||
use Psr\Container\ContainerInterface; | ||
|
||
/** | ||
* PluginContainerInterface | ||
* | ||
* This interface represents a container for managing services and dependencies related to an ILIAS plugin. | ||
* | ||
* @author Thomas Joußen <[email protected]> | ||
*/ | ||
interface PluginContainerInterface | ||
{ | ||
/** | ||
* Register a service in the container. | ||
* | ||
* @param string $id The key to access the service. | ||
* @param callable $factory The function to register the service. | ||
* | ||
* @return self | ||
*/ | ||
public function register(string $id, callable $factory): self; | ||
|
||
/** | ||
* Get the core DI container. | ||
* | ||
* @return Container The ILIAS DI container. | ||
*/ | ||
public function core(): Container; | ||
|
||
/** | ||
* Get the plugin DI container. | ||
* | ||
* @return ContainerInterface The Plugin DI container. | ||
*/ | ||
public function plugin(): ContainerInterface; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
/* | ||
* This file is part of the ilias-plugin-utils Library for ILIAS. | ||
* | ||
* (c) Thomas Joußen <[email protected]> | ||
* | ||
* This source file is subject to the GPL-3.0 license that is bundled | ||
* with this source code in the file LICENSE. | ||
*/ | ||
|
||
namespace Thojou\Ilias\Plugin\Utils\DI; | ||
|
||
use Psr\Container\NotFoundExceptionInterface; | ||
|
||
/** | ||
* PluginContainerNotFoundException | ||
* | ||
* This class represents an exception that is thrown when the entry was not found in the container. | ||
* | ||
* @author Thomas Joußen <[email protected]> | ||
* @see https://www.php-fig.org/psr/psr-11/#33-psrcontainernotfoundexceptioninterface | ||
*/ | ||
class PluginContainerNotFoundException extends \Exception implements NotFoundExceptionInterface | ||
{ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,30 +14,41 @@ | |
namespace Thojou\Ilias\Plugin\Utils\DI; | ||
|
||
use ILIAS\DI\Container; | ||
|
||
use Psr\Container\ContainerInterface; | ||
use RuntimeException; | ||
|
||
use function is_object; | ||
|
||
/** | ||
* PluginContainer | ||
* PluginContainerTrait | ||
* | ||
* This class represents a container for managing services and dependencies related to an ILIAS plugin. | ||
* This trait represents a container for managing services and dependencies related to an ILIAS plugin. | ||
* The PluginContainerTrait provides the implementation of the PluginContainerInterface. | ||
* | ||
* @author Thomas Joußen <[email protected]> | ||
*/ | ||
class PluginContainer | ||
trait PluginContainerTrait | ||
{ | ||
/** | ||
* @var PluginContainer|null A singleton instance of the PluginContainer class. | ||
* @var PluginContainerInterface|null A singleton instance of the PluginContainer class. | ||
*/ | ||
private static ?PluginContainer $instance = null; | ||
private static ?PluginContainerInterface $instance = null; | ||
|
||
/** | ||
* @var Container The DI (Dependency Injection) container. | ||
*/ | ||
private Container $dic; | ||
|
||
/** | ||
* @var ContainerInterface The core DI container. | ||
*/ | ||
private ContainerInterface $core; | ||
|
||
/** | ||
* @var ContainerInterface The plugin DI container. | ||
*/ | ||
private ContainerInterface $plugin; | ||
|
||
/** | ||
* @var string The ID of the associated plugin. | ||
*/ | ||
|
@@ -49,20 +60,20 @@ class PluginContainer | |
* @param Container $dic The DI container to be used. | ||
* @param string $pluginId The ID of the associated plugin. | ||
* | ||
* @return self | ||
* @return PluginContainerInterface | ||
*/ | ||
public static function init(Container $dic, string $pluginId): self | ||
public static function init(Container $dic, string $pluginId): PluginContainerInterface | ||
{ | ||
return self::$instance = new self($dic, $pluginId); | ||
} | ||
|
||
/** | ||
* Get the singleton instance of PluginContainer. | ||
* | ||
* @return self | ||
* @return PluginContainerInterface | ||
* @throws RuntimeException If the PluginContainer is not initialized. | ||
*/ | ||
public static function get(): self | ||
public static function get(): PluginContainerInterface | ||
{ | ||
if (!self::$instance) { | ||
throw new RuntimeException('PluginContainer not initialized'); | ||
|
@@ -80,50 +91,40 @@ private function __construct(Container $dic, string $pluginId) | |
{ | ||
$this->pluginId = $pluginId; | ||
$this->dic = $dic; | ||
$this->plugin = new PluginContainerWrapper($dic, $pluginId); | ||
} | ||
|
||
/** | ||
* Get the core DI container. | ||
* | ||
* @return Container The DI container. | ||
* @return Container The ILIAS DI container. | ||
*/ | ||
public function core(): Container | ||
{ | ||
return $this->dic; | ||
} | ||
|
||
/** | ||
* Get a service from the container. | ||
* | ||
* @template T of object | ||
* | ||
* @param class-string<T> $key The key to access the service. | ||
* Get the plugin DI container. | ||
* | ||
* @return T The requested service. | ||
* @throws RuntimeException If the service is not found. | ||
* @return ContainerInterface The Plugin DI container. | ||
*/ | ||
public function getService(string $key): object | ||
public function plugin(): ContainerInterface | ||
{ | ||
$service = $this->dic[$this->pluginId . '.' . $key]; | ||
|
||
if (!is_object($service)) { | ||
throw new RuntimeException("Service $key not found for plugin $this->pluginId"); | ||
} | ||
|
||
return $service; //@phpstan-ignore-line | ||
return $this->plugin; | ||
} | ||
|
||
/** | ||
* Register a service in the container. | ||
* | ||
* @param string $key The key to access the service. | ||
* @param callable $registerFunction The function to register the service. | ||
* @param string $id The key to access the service. | ||
* @param callable $factory The function to register the service. | ||
* | ||
* @return self | ||
*/ | ||
public function register(string $key, callable $registerFunction): self | ||
public function register(string $id, callable $factory): self | ||
{ | ||
$this->dic[$this->pluginId . '.' . $key] = $registerFunction; | ||
$this->dic[$this->pluginId . '.' . $id] = $factory; | ||
|
||
return $this; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
/* | ||
* This file is part of the ilias-plugin-utils Library for ILIAS. | ||
* | ||
* (c) Thomas Joußen <[email protected]> | ||
* | ||
* This source file is subject to the GPL-3.0 license that is bundled | ||
* with this source code in the file LICENSE. | ||
*/ | ||
|
||
namespace Thojou\Ilias\Plugin\Utils\DI; | ||
|
||
use Exception; | ||
use ILIAS\DI\Container; | ||
use Psr\Container\ContainerInterface; | ||
|
||
/** | ||
* PluginContainerWrapper | ||
* | ||
* This class represents a wrapper for the ILIAS container to make it compatible with the PSR-11 container interface. | ||
* | ||
* @author Thomas Joußen <[email protected]> | ||
*/ | ||
class PluginContainerWrapper implements ContainerInterface | ||
{ | ||
/** | ||
* @var Container The ILIAS container. | ||
*/ | ||
private Container $container; | ||
|
||
/** | ||
* @var string|null The key prefix for the container. | ||
*/ | ||
private ?string $keyPrefix; | ||
|
||
/** | ||
* PluginContainerWrapper constructor. | ||
* | ||
* @param Container $container The ILIAS container. | ||
* @param string|null $keyPrefix The key prefix for the container. | ||
*/ | ||
public function __construct( | ||
Container $container, | ||
?string $keyPrefix = null | ||
) { | ||
$this->container = $container; | ||
$this->keyPrefix = $keyPrefix; | ||
} | ||
|
||
/** | ||
* Get a service from the container. | ||
* | ||
* @param class-string<T> $id The id to access the service. | ||
* | ||
* @template T of mixed | ||
* | ||
* @return T The requested service. | ||
* @throws PluginContainerException | ||
* @throws PluginContainerNotFoundException | ||
*/ | ||
public function get(string $id) | ||
{ | ||
$id = $this->resolveId($id); | ||
|
||
if(!$this->has($id)) { | ||
throw new PluginContainerNotFoundException("Service with id '$id' not found in PluginContainer."); | ||
} | ||
|
||
try { | ||
return $this->container[$id]; | ||
} catch (Exception $e) { // @phpstan-ignore-line | ||
throw new PluginContainerException("Error while getting service with id '$id' from PluginContainer.", 0, $e); | ||
} | ||
} | ||
|
||
/** | ||
* Check if a service is registered in the container. | ||
* | ||
* @param string $id The id to access the service. | ||
* | ||
* @return bool True if the service is registered, false otherwise. | ||
*/ | ||
public function has(string $id): bool | ||
{ | ||
$id = $this->resolveId($id); | ||
|
||
return isset($this->container[$id]); | ||
} | ||
|
||
/** | ||
* Resolve the id with the key prefix. | ||
* | ||
* @param string $id | ||
* | ||
* @return string | ||
*/ | ||
private function resolveId(string $id): string | ||
{ | ||
if ($this->keyPrefix === null) { | ||
return $id; | ||
} | ||
|
||
return sprintf("%s.%s", $this->keyPrefix, $id); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?php | ||
|
||
namespace Thojou\Ilias\Plugin\Utils\Tests\DI\Fixtures; | ||
|
||
use Thojou\Ilias\Plugin\Utils\DI\PluginContainerInterface; | ||
use Thojou\Ilias\Plugin\Utils\DI\PluginContainerTrait; | ||
|
||
class TestPluginContainer implements PluginContainerInterface | ||
{ | ||
use PluginContainerTrait; | ||
} |
Oops, something went wrong.