Introduce ContainerWrapper

Container wrapper wraps both premium and free containers and adds ability for free plugin to use premium plugin services directly.
[PREMIUM-99]
This commit is contained in:
Rostislav Wolny
2018-12-04 14:46:14 +01:00
parent 884cabb51f
commit 26472d8b9a
5 changed files with 154 additions and 14 deletions

View File

@ -2,9 +2,9 @@
namespace MailPoet\API;
use MailPoet\DI\ContainerWrapper;
use MailPoetVendor\Psr\Container\ContainerInterface;
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use MailPoet\DI\ContainerFactory;
if(!defined('ABSPATH')) exit;
@ -37,8 +37,7 @@ class API {
*/
private static function ensureContainerIsLoaded() {
if(!self::$container) {
$factory = new ContainerFactory();
self::$container = $factory->getContainer();
self::$container = ContainerWrapper::getInstance();
}
}
}

View File

@ -3,7 +3,6 @@ namespace MailPoet\API\JSON;
use MailPoet\Config\AccessControl;
use MailPoetVendor\Psr\Container\ContainerInterface;
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use MailPoet\Models\Setting;
use MailPoet\Util\Helpers;
use MailPoet\Util\Security;
@ -143,13 +142,7 @@ class API {
throw new \Exception(__('Invalid API endpoint.', 'mailpoet'));
}
try {
$endpoint = $this->container->get($this->_request_endpoint_class);
} catch (ServiceNotFoundException $e) {
// Hotfix for Premium plugin which adds endpoints which are not registered in DI container
$endpoint = new $this->_request_endpoint_class();
}
if(!method_exists($endpoint, $this->_request_method)) {
throw new \Exception(__('Invalid API endpoint method.', 'mailpoet'));
}

View File

@ -4,7 +4,7 @@ namespace MailPoet\Config;
use MailPoet\API;
use MailPoet\Cron\CronTrigger;
use MailPoet\DI\ContainerFactory;
use MailPoet\DI\ContainerWrapper;
use MailPoet\Models\Setting;
use MailPoet\Router;
use MailPoet\Util\ConflictResolver;
@ -97,8 +97,7 @@ class Initializer {
}
function loadContainer() {
$container_factory = new ContainerFactory(WP_DEBUG);
$this->container = $container_factory->getContainer();
$this->container = ContainerWrapper::getInstance(WP_DEBUG);
API\API::injectContainer($this->container);
}

View File

@ -0,0 +1,62 @@
<?php
namespace MailPoet\DI;
use MailPoetVendor\Psr\Container\ContainerInterface;
use MailPoetVendor\Psr\Container\NotFoundExceptionInterface;
class ContainerWrapper implements ContainerInterface {
/** @var ContainerInterface */
private $free_container;
/** @var ContainerInterface|null */
private $premium_container;
/** @var ContainerWrapper */
private static $instance;
public function __construct(ContainerInterface $free_container, ContainerInterface $premium_container = null) {
$this->free_container = $free_container;
$this->premium_container = $premium_container;
}
function get($id) {
try {
return $this->free_container->get($id);
} catch (NotFoundExceptionInterface $e) {
if(!$this->premium_container) {
throw $e;
}
return $this->premium_container->get($id);
}
}
function has($id) {
return $this->free_container->has($id) || ($this->premium_container && $this->premium_container->has($id));
}
/**
* @return ContainerInterface|null
*/
function getPremiumContainer() {
return $this->premium_container;
}
static function getInstance($debug = false) {
if(self::$instance) {
return self::$instance;
}
$free_container_factory = new ContainerFactory(new ContainerConfigurator(), $debug);
$free_container = $free_container_factory->getContainer();
$premium_container = null;
if(class_exists(\MailPoet\Premium\DI\ContainerConfigurator::class)) {
$premium_container_factory = new ContainerFactory(new \MailPoet\Premium\DI\ContainerConfigurator($free_container), $debug);
$premium_container = $premium_container_factory->getContainer();
$premium_container->set(IContainerConfigurator::FREE_CONTAINER_SERVICE_SLUG, $free_container);
$free_container->set(IContainerConfigurator::PREMIUM_CONTAINER_SERVICE_SLUG, $premium_container);
}
self::$instance = new ContainerWrapper($free_container, $premium_container);
return self::$instance;
}
}

View File

@ -0,0 +1,87 @@
<?php
namespace MailPoet\Test\DI;
use Codeception\Stub;
use MailPoet\DI\ContainerWrapper;
use MailPoetVendor\Symfony\Component\DependencyInjection\Container;
use MailPoetVendor\Symfony\Component\DependencyInjection\ContainerBuilder;
use MailPoetVendor\Psr\Container\ContainerInterface;
use MailPoetVendor\Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
class ContainerWrapperTest extends \MailPoetUnitTest {
function testItCanConstruct() {
$instance = new ContainerWrapper(new ContainerBuilder());
expect($instance)->isInstanceOf(ContainerWrapper::class);
expect($instance)->isInstanceOf(ContainerInterface::class);
$instance = new ContainerWrapper(new ContainerBuilder(), new ContainerBuilder());
expect($instance)->isInstanceOf(ContainerWrapper::class);
expect($instance)->isInstanceOf(ContainerInterface::class);
}
function testItProvidesPremiumContainerIfAvailable() {
$instance = new ContainerWrapper(new ContainerBuilder());
expect($instance->getPremiumContainer())->null();
$instance = new ContainerWrapper(new ContainerBuilder(), new ContainerBuilder());
expect($instance->getPremiumContainer())->isInstanceOf(ContainerBuilder::class);
}
function testItProvidesFreePluginServices() {
$free_container_stub = Stub::make(Container::class, [
'get' => function () {
return 'service';
}
]);
$instance = new ContainerWrapper($free_container_stub);
$service = $instance->get('service_id');
expect($service)->equals('service');
}
function testItThrowsFreePluginServices() {
$free_container_stub = Stub::make(Container::class, [
'get' => function ($id) {
throw new ServiceNotFoundException($id);
}
]);
$instance = new ContainerWrapper($free_container_stub);
$exception = null;
try {
$instance->get('service');
} catch (ServiceNotFoundException $e) {
$exception = $e;
}
expect($exception)->isInstanceOf(ServiceNotFoundException::class);
}
function testItReturnServiceFromPremium() {
$free_container_stub = Stub::make(Container::class, [
'get' => function ($id) {
throw new ServiceNotFoundException($id);
}
]);
$premium_container_stub = Stub::make(Container::class, [
'get' => function () {
return 'service_1';
}
]);
$instance = new ContainerWrapper($free_container_stub, $premium_container_stub);
expect($instance->get('service'))->equals('service_1');
}
function testItThrowsIfServiceNotFoundInBothContainers() {
$container_stub = Stub::make(Container::class, [
'get' => function ($id) {
throw new ServiceNotFoundException($id);
}
]);
$instance = new ContainerWrapper($container_stub, $container_stub);
$exception = null;
try {
$instance->get('service');
} catch (ServiceNotFoundException $e) {
$exception = $e;
}
expect($exception)->isInstanceOf(ServiceNotFoundException::class);
}
}