Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add lazy decorator #116

Closed
wants to merge 10 commits into from
Closed
4 changes: 4 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,17 @@
},
"require-dev": {
"maglnet/composer-require-checker": "^4.2",
"ocramius/proxy-manager": "^2.13",
"phpunit/phpunit": "^9.5",
"rector/rector": "^0.14.3",
"roave/infection-static-analysis-plugin": "^1.16",
"spatie/phpunit-watcher": "^1.23",
"vimeo/psalm": "^4.18",
"yiisoft/test-support": "^1.3"
},
"suggest": {
"ocramius/proxy-manager": "Install this package if you want to use lazy loading."
},
"autoload": {
"psr-4": {
"Yiisoft\\Factory\\": "src"
Expand Down
26 changes: 26 additions & 0 deletions src/Definition/Decorator/LazyDefinitionDecorator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Factory\Definition\Decorator;

use ProxyManager\Factory\LazyLoadingValueHolderFactory;
use Psr\Container\ContainerInterface;
use Yiisoft\Definitions\Contract\DefinitionInterface;

final class LazyDefinitionDecorator implements DefinitionInterface
{
public function __construct(private LazyLoadingValueHolderFactory $factory, private DefinitionInterface $definition, private string $objectClass)
{
}

public function resolve(ContainerInterface $container): mixed
{
return $this->factory->createProxy(
$this->objectClass,
function (&$wrappedObject) use ($container) {
$wrappedObject = $this->definition->resolve($container);
}
);
}
}
20 changes: 20 additions & 0 deletions tests/Support/NotFinalClass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Factory\Tests\Support;

class NotFinalClass
{
private $arguments;

public function __construct(...$arguments)
{
$this->arguments = $arguments;
}

public function getArguments(): array
{
return $this->arguments;
}
}
69 changes: 69 additions & 0 deletions tests/Unit/Definition/Decorator/LazyDefinitionDecoratorTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Factory\Tests\Unit\Definition;

use PHPUnit\Framework\TestCase;
use ProxyManager\Exception\InvalidProxiedClassException;
use ProxyManager\Factory\LazyLoadingValueHolderFactory;
use ProxyManager\Proxy\LazyLoadingInterface;
use Yiisoft\Definitions\ArrayDefinition;
use Yiisoft\Factory\Definition\Decorator\LazyDefinitionDecorator;
use Yiisoft\Factory\Tests\Support\EngineInterface;
use Yiisoft\Factory\Tests\Support\NotFinalClass;
use Yiisoft\Factory\Tests\Support\Phone;
use Yiisoft\Test\Support\Container\SimpleContainer;

final class LazyDefinitionDecoratorTest extends TestCase
{
public function testDecorateFinalClass(): void
{
$container = new SimpleContainer();
$factory = new LazyLoadingValueHolderFactory();

$class = Phone::class;

$definition = ArrayDefinition::fromConfig([
ArrayDefinition::CLASS_NAME => $class,
]);
$definition = new LazyDefinitionDecorator($factory, $definition, $class);

$this->expectException(InvalidProxiedClassException::class);
$definition->resolve($container);
}

public function testDecorateNotFinalClass(): void
{
$container = new SimpleContainer();
$factory = new LazyLoadingValueHolderFactory();

$class = NotFinalClass::class;

$definition = ArrayDefinition::fromConfig([
ArrayDefinition::CLASS_NAME => $class,
]);
$definition = new LazyDefinitionDecorator($factory, $definition, $class);

$phone = $definition->resolve($container);

self::assertInstanceOf(LazyLoadingInterface::class, $phone);
}

public function testDecorateInterface(): void
{
$container = new SimpleContainer();
$factory = new LazyLoadingValueHolderFactory();

$class = EngineInterface::class;

$definition = ArrayDefinition::fromConfig([
ArrayDefinition::CLASS_NAME => $class,
]);
$definition = new LazyDefinitionDecorator($factory, $definition, $class);

$phone = $definition->resolve($container);

self::assertInstanceOf(LazyLoadingInterface::class, $phone);
}
}