Skip to content

Commit

Permalink
Merge pull request #105 from thefrosty/develop
Browse files Browse the repository at this point in the history
Add Legacy PSR Container Support (#103)
  • Loading branch information
thefrosty authored Aug 8, 2022
2 parents c887c43 + 93cce43 commit 07b14ed
Show file tree
Hide file tree
Showing 10 changed files with 156 additions and 42 deletions.
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
},
"optimize-autoloader": true,
"platform": {
"php": "7.4.26"
"php": "7.4"
},
"sort-packages": true
},
Expand All @@ -28,7 +28,7 @@
"ext-json": "*",
"ext-openssl": "*",
"johnbillion/args": "^1.1",
"psr/container": "^2.0.2"
"psr/container": "^1.0 || ^2.0"
},
"require-dev": {
"ext-simplexml": "*",
Expand Down
10 changes: 5 additions & 5 deletions src/Plugin/AbstractContainerProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace TheFrosty\WpUtilities\Plugin;

use Psr\Container\ContainerInterface;

/**
* Class AbstractContainerProvider
* @package TheFrosty\WpUtilities\Plugin
Expand All @@ -12,13 +14,11 @@ abstract class AbstractContainerProvider implements WpHooksInterface, PluginAwar

/**
* AbstractContainerProvider constructor.
* @param Container|null $container Set the container, or use `$this->setContainer($container)`.
* @param Container|ContainerInterface|null $container Set the container, or use `$this->setContainer($container)`.
*/
public function __construct(?Container $container = null)
public function __construct(?ContainerInterface $container = null)
{
if ($container) {
$this->setContainer($container);
}
$this->setContainer($container);
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/Plugin/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@

/**
* Container class.
* Extends Pimple to satisfy the ContainerInterface.
* Extends Pimple to satisfy the ContainerInterface >= v2.0.0.
* @ref https://github.com/php-fig/container/blob/2.0.0/src/ContainerInterface.php
* @package TheFrosty\WpUtilities\Plugin
* @SuppressWarnings(PHPMD.ShortVariable)
*/
class Container extends Pimple implements ContainerInterface
{
Expand Down
47 changes: 47 additions & 0 deletions src/Plugin/Container100.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php declare(strict_types=1);

namespace TheFrosty\WpUtilities\Plugin;

use Pimple\Container as Pimple;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\ContainerInterface;
use Psr\Container\NotFoundExceptionInterface;

/**
* Container100 class.
* Extends Pimple to satisfy the ContainerInterface v1.0.0.
* @ref https://github.com/php-fig/container/blob/1.0.0/src/ContainerInterface.php
* @package TheFrosty\WpUtilities\Plugin
*/
class Container100 extends Pimple implements ContainerInterface
{

/**
* Finds an entry of the container by its identifier and returns it.
*
* @param string $id Identifier of the entry to look for.
*
* @return mixed Entry.
* @throws ContainerExceptionInterface Error while retrieving the entry.
* @throws NotFoundExceptionInterface No entry was found for **this** identifier.
*/
public function get($id)
{
return $this->offsetGet($id);
}

/**
* Returns true if the container can return an entry for the given identifier.
* Returns false otherwise.
*
* `has($id)` returning true does not mean that `get($id)` will not throw an exception.
* It does however mean that `get($id)` will not throw a `NotFoundExceptionInterface`.
*
* @param string $id Identifier of the entry to look for.
* @return bool
*/
public function has($id)
{
return $this->offsetExists($id);
}
}
47 changes: 47 additions & 0 deletions src/Plugin/Container110.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php declare(strict_types=1);

namespace TheFrosty\WpUtilities\Plugin;

use Pimple\Container as Pimple;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\ContainerInterface;
use Psr\Container\NotFoundExceptionInterface;

/**
* Container110 class.
* Extends Pimple to satisfy the ContainerInterface v1.1.0
* @ref https://github.com/php-fig/container/blob/1.1.0/src/ContainerInterface.php.
* @package TheFrosty\WpUtilities\Plugin
*/
class Container110 extends Pimple implements ContainerInterface
{

/**
* Finds an entry of the container by its identifier and returns it.
*
* @param string $id Identifier of the entry to look for.
*
* @return mixed Entry.
* @throws ContainerExceptionInterface Error while retrieving the entry.
* @throws NotFoundExceptionInterface No entry was found for **this** identifier.
*/
public function get(string $id)
{
return $this->offsetGet($id);
}

/**
* Returns true if the container can return an entry for the given identifier.
* Returns false otherwise.
*
* `has($id)` returning true does not mean that `get($id)` will not throw an exception.
* It does however mean that `get($id)` will not throw a `NotFoundExceptionInterface`.
*
* @param string $id Identifier of the entry to look for.
* @return bool
*/
public function has(string $id)
{
return $this->offsetExists($id);
}
}
20 changes: 10 additions & 10 deletions src/Plugin/ContainerAwareTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ trait ContainerAwareTrait
{

/**
* Container.
* @var ContainerInterface
* Container instance.
* @var ContainerInterface|null
*/
private ContainerInterface $container;
private ?ContainerInterface $container;

/**
* Proxy access to container services.
Expand All @@ -29,7 +29,7 @@ trait ContainerAwareTrait
*/
public function __get(string $name)
{
return $this->container->get($name);
return $this->container && $this->container->get($name);
}

/**
Expand All @@ -40,7 +40,7 @@ public function __get(string $name)
*/
public function __isset(string $name): bool
{
return $this->container->has($name);
return $this->container && $this->container->has($name);
}

/**
Expand All @@ -53,7 +53,7 @@ public function __isset(string $name): bool
*/
public function __call(string $method, array $args)
{
if ($this->container->has($method)) {
if ($this->container && $this->container->has($method)) {
$object = $this->container->get($method);
if (\is_callable($object)) {
return \call_user_func_array($object, $args);
Expand All @@ -66,20 +66,20 @@ public function __call(string $method, array $args)
/**
* Enable access to the DI container by plugin consumers.
*
* @return ContainerInterface
* @return ContainerInterface|null
*/
public function getContainer(): ContainerInterface
public function getContainer(): ?ContainerInterface
{
return $this->container;
}

/**
* Set the container.
*
* @param ContainerInterface $container Dependency injection container.
* @param ContainerInterface|null $container Dependency injection container.
* @return $this
*/
public function setContainer(ContainerInterface $container): self
public function setContainer(?ContainerInterface $container = null): self
{
$this->container = $container;

Expand Down
36 changes: 28 additions & 8 deletions src/Plugin/PluginFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace TheFrosty\WpUtilities\Plugin;

use Psr\Container\ContainerInterface;
use ReflectionMethod;

/**
* Class PluginFactory
Expand Down Expand Up @@ -34,18 +35,17 @@ public static function getInstance(string $slug): Plugin
* @param string $slug Plugin slug.
* @param string|null $filename Optional. Absolute path to the main plugin file.
* This should be passed if the calling file is not the main plugin file.
* @param ContainerInterface|null $container
* @return Plugin A Plugin object instance.
*/
public static function create(string $slug, ?string $filename = '', ?ContainerInterface $container = null): Plugin
public static function create(string $slug, ?string $filename = ''): Plugin
{
if (isset(self::$instances[$slug]) && self::$instances[$slug] instanceof Plugin) {
return self::$instances[$slug];
}
// Use the calling file as the main plugin file.
if (empty($filename)) {
// @codingStandardsIgnoreStart
$backtrace = \debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1);
$backtrace = \debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 1);
$filename = $backtrace[0]['file'];
// @codingStandardsIgnoreEnd
}
Expand All @@ -58,7 +58,7 @@ public static function create(string $slug, ?string $filename = '', ?ContainerIn
->setSlug($slug)
->setUrl(\plugin_dir_url($filename));

$plugin = self::setContainer($plugin, $container);
$plugin = self::setContainer($plugin);
$plugin->setTemplateLoader(new TemplateLoader($plugin));
self::$instances[$slug] = $plugin;

Expand All @@ -69,15 +69,35 @@ public static function create(string $slug, ?string $filename = '', ?ContainerIn
* Set the Pimple\Container if it's available.
*
* @param Plugin $plugin
* @param ContainerInterface|null $container
* @return Plugin
*/
private static function setContainer(Plugin $plugin, ?ContainerInterface $container = null): Plugin
private static function setContainer(Plugin $plugin): Plugin
{
if (\class_exists('\Pimple\Container') && \interface_exists('\Psr\Container\ContainerInterface')) {
$plugin->setContainer($container ?? new Container());
if (
\class_exists('\Pimple\Container') &&
\interface_exists('\Psr\Container\ContainerInterface')
) {
$plugin->setContainer(self::getContainer());
}

return $plugin;
}

/**
* Return a "Container" stub for ContainerInterface v1.0.0, v1.1.0 and/or >= v2.0.0.
* @return ContainerInterface
*/
private static function getContainer(): ContainerInterface
{
$reflection = new ReflectionMethod('\Psr\Container\ContainerInterface', 'has');
if ($reflection->hasReturnType() && $reflection->getReturnType()) {
return new Container(); // ContainerInterface >= 2.0.0
}
$parameter = $reflection->getParameters()[0] ?? null;
if ($parameter && $parameter->getType() && $parameter->getType()->getName() === 'string') {
return new Container110();
}

return new Container100();
}
}
4 changes: 2 additions & 2 deletions tests/unit/Plugin/HooksTraitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public function testRegisterFilters(): void
{
$provider = $this->getMockProvider(HookProvider::class);
$provider->expects($this->exactly(1))
->method('addFilter')
->method(self::METHOD_ADD_FILTER)
->will($this->returnCallback(function ($hook, $method, $priority, $arg_count) {
TestCase::assertSame('theTitle', $hook);
TestCase::assertSame(10, $priority);
Expand All @@ -38,7 +38,7 @@ public function testRegisterActions(): void
{
$provider = $this->getMockProvider(HookProvider::class);
$provider->expects($this->exactly(1))
->method('addFilter')
->method(self::METHOD_ADD_FILTER)
->will($this->returnCallback(function ($hook, $method, $priority, $arg_count) {
TestCase::assertSame('template_redirect', $hook);
TestCase::assertSame(10, $priority);
Expand Down
21 changes: 10 additions & 11 deletions tests/unit/Plugin/PluginAwareTraitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace TheFrosty\WpUtilities\Tests\Plugin;

use ReflectionClass;
use TheFrosty\WpUtilities\Plugin\Plugin;
use TheFrosty\WpUtilities\Plugin\PluginAwareTrait;
use TheFrosty\WpUtilities\Tests\Plugin\Framework\TestCase;
Expand All @@ -15,26 +16,24 @@ class PluginAwareTraitTest extends TestCase
{

/**
* Test set_plugin()
* Test setPlugin()
*/
public function test_set_plugin()
public function testSetPlugin(): void
{
$provider = $this->getMockForTrait(PluginAwareTrait::class);
$provider = new class {

try {
$class = new \ReflectionClass($provider);
$property = $class->getProperty('plugin');
$property->setAccessible(true);
} catch (\ReflectionException $exception) {
$this->assertInstanceOf(\ReflectionException::class, $exception);
use PluginAwareTrait;
};

return;
}
$class = new ReflectionClass($provider);
$property = $class->getProperty('plugin');
$property->setAccessible(true);

$plugin = new Plugin();
/** PluginAwareTrait @var PluginAwareTrait $provider */
$provider->setPlugin($plugin);

$this->assertSame($plugin, $property->getValue($provider));
$this->assertSame($plugin, $provider->getPlugin());
}
}
5 changes: 3 additions & 2 deletions tests/unit/Plugin/PluginRegisterHooksTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace TheFrosty\WpUtilities\Tests\Plugin;

use ReflectionClass;
use TheFrosty\WpUtilities\Plugin\WpHooksInterface;
use TheFrosty\WpUtilities\Plugin\AbstractHookProvider;
use TheFrosty\WpUtilities\Plugin\Plugin;
Expand All @@ -17,12 +18,12 @@ class PluginRegisterHooksTest extends TestCase
/**
* Test AbstractHookProvider
*/
public function test_register_hooks(): void
public function testRegisterHooks(): void
{
$provider = $this->getMockProviderForAbstractClass(AbstractHookProvider::class);

try {
$class = new \ReflectionClass($provider);
$class = new ReflectionClass($provider);
$property = $class->getProperty('plugin');
$property->setAccessible(true);
} catch (\ReflectionException $exception) {
Expand Down

0 comments on commit 07b14ed

Please sign in to comment.