Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
8679688
Add lazy definition
xepozz Nov 20, 2022
a783c5d
Apply fixes from StyleCI
StyleCIBot Nov 20, 2022
5ccf19c
Add missed files
xepozz Nov 20, 2022
908b4d6
Merge remote-tracking branch 'origin/lazy-definition' into lazy-defin…
xepozz Nov 20, 2022
5d6b89f
Fix decorator
xepozz Nov 20, 2022
f5225c2
[ci-review] Apply changes from Rector action.
Nov 20, 2022
8dbcf88
Add suggest section
xepozz Nov 20, 2022
9bd5fb3
Merge remote-tracking branch 'origin/lazy-definition' into lazy-defin…
xepozz Nov 20, 2022
690a335
Merge branch 'master' into lazy-definition
xepozz Dec 3, 2022
f034ae0
Use `friendsofphp/proxy-manager-lts` package
xepozz Dec 3, 2022
e03e225
Rework lazy definition
xepozz Dec 3, 2022
6a8f40e
Apply fixes from StyleCI
StyleCIBot Jul 1, 2023
f7aba27
Merge branch 'master' into lazy-definition
xepozz Jul 29, 2023
de1c7e8
Apply Rector changes (CI)
xepozz Jul 29, 2023
bd65bf9
Add php 8.2 in CI
xepozz Jul 29, 2023
fba80b0
Add php 8.2 in CI
xepozz Jul 29, 2023
a4e6abc
Merge remote-tracking branch 'origin/lazy-definition' into lazy-defin…
xepozz Jul 29, 2023
4ced43c
Fix tests and psalm errors
xepozz Jul 29, 2023
2ca1b5e
Apply suggestions from code review
xepozz Aug 1, 2023
e1d4093
Apply PR suggestions
xepozz Aug 1, 2023
baee300
Add composer-require-checker.json
xepozz Aug 1, 2023
3f99488
Fix null class property
xepozz Aug 1, 2023
bc09d53
Apply fixes from StyleCI
StyleCIBot Aug 1, 2023
cbc4373
Add a hack for already normalized configs
xepozz Aug 1, 2023
fd066f1
Merge branch 'lazy-definition' of github.com:yiisoft/definitions into…
xepozz Aug 1, 2023
6060238
Apply fixes from StyleCI
StyleCIBot Aug 1, 2023
6d4696e
Fix psalm
xepozz Aug 2, 2023
bb401d9
Merge branch 'lazy-definition' of github.com:yiisoft/definitions into…
xepozz Aug 2, 2023
41eef65
Remove PHP 8.2 from psalm CI
xepozz Aug 2, 2023
7993b9b
Merge branch 'master' into lazy-definition
xepozz Aug 2, 2023
29f4c54
Fix psalm error
xepozz Aug 19, 2023
4128323
Merge branch 'master' into lazy-definition
xepozz Aug 19, 2023
e6c3e9b
Merge branch 'master' into lazy-definition
xepozz Mar 3, 2024
23e3ff7
improve
vjik Mar 3, 2024
69be227
Merge pull request #88 from yiisoft/lazy-suggestion
xepozz Apr 16, 2024
5434734
Merge branch 'master' into lazy-definition
xepozz Apr 16, 2024
cf7935f
Apply fixes from StyleCI
StyleCIBot Apr 16, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions composer-require-checker.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"symbol-whitelist": [
"ProxyManager\\Factory\\LazyLoadingValueHolderFactory",
"ProxyManager\\Proxy\\VirtualProxyInterface"
],
"php-core-extensions": [
"Core",
"date",
"json",
"pcre",
"Phar",
"Reflection",
"SPL",
"standard"
],
"scan-files": []
}
4 changes: 4 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,17 @@
},
"require-dev": {
"maglnet/composer-require-checker": "^4.2",
"friendsofphp/proxy-manager-lts": "^1.0",
"phpunit/phpunit": "^9.5",
"rector/rector": "^1.0.0",
"roave/infection-static-analysis-plugin": "^1.18",
"spatie/phpunit-watcher": "^1.23",
"vimeo/psalm": "^4.30|^5.21",
"yiisoft/test-support": "^1.4"
},
"suggest": {
"friendsofphp/proxy-manager-lts": "Allows use lazy definitions"
},
"autoload": {
"psr-4": {
"Yiisoft\\Definitions\\": "src"
Expand Down
4 changes: 2 additions & 2 deletions src/ArrayDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public function withReferenceContainer(?ContainerInterface $referenceContainer):
}

/**
* Create ArrayDefinition from array config.
* Create `ArrayDefinition` from array config.
*
* @psalm-param ArrayDefinitionConfig $config
*/
Expand All @@ -69,7 +69,7 @@ public static function fromConfig(array $config): self
return new self(
$config[self::CLASS_NAME],
$config[self::CONSTRUCTOR] ?? [],
self::getMethodsAndPropertiesFromConfig($config)
self::getMethodsAndPropertiesFromConfig($config),
);
}

Expand Down
1 change: 1 addition & 0 deletions src/CallableDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ final class CallableDefinition implements DefinitionInterface
{
/**
* @var array|callable
*
* @psalm-var callable|array{0:class-string,1:string}
*/
private $callable;
Expand Down
2 changes: 2 additions & 0 deletions src/Helpers/DefinitionExtractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ final class DefinitionExtractor
* @throws NotInstantiableException
*
* @return ParameterDefinition[]
*
* @psalm-return array<string, ParameterDefinition>
*/
public static function fromClassName(string $class): array
Expand Down Expand Up @@ -61,6 +62,7 @@ public static function fromClassName(string $class): array
* Extract dependency definitions from type hints of a function.
*
* @return ParameterDefinition[]
*
* @psalm-return array<string, ParameterDefinition>
*/
public static function fromFunction(ReflectionFunctionAbstract $reflectionFunction): array
Expand Down
7 changes: 3 additions & 4 deletions src/Helpers/Normalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
use Yiisoft\Definitions\Reference;
use Yiisoft\Definitions\ValueDefinition;

use function array_key_exists;
use function is_array;
use function is_callable;
use function is_object;
Expand Down Expand Up @@ -49,7 +48,7 @@ final class Normalizer
public static function normalize(mixed $definition, ?string $class = null): DefinitionInterface
{
// Reference
if ($definition instanceof ReferenceInterface) {
if ($definition instanceof DefinitionInterface) {
return $definition;
}

Expand All @@ -75,7 +74,7 @@ public static function normalize(mixed $definition, ?string $class = null): Defi
// Array definition
if (is_array($definition)) {
$config = $definition;
if (!array_key_exists(ArrayDefinition::CLASS_NAME, $config)) {
if (!isset($config[ArrayDefinition::CLASS_NAME])) {
if ($class === null) {
throw new InvalidConfigException(
'Array definition should contain the key "class": ' . var_export($definition, true)
Expand All @@ -88,7 +87,7 @@ public static function normalize(mixed $definition, ?string $class = null): Defi
}

// Ready object
if (is_object($definition) && !($definition instanceof DefinitionInterface)) {
if (is_object($definition)) {
return new ValueDefinition($definition);
}

Expand Down
39 changes: 39 additions & 0 deletions src/LazyDefinition.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Definitions;

use ProxyManager\Factory\LazyLoadingValueHolderFactory;
use ProxyManager\Proxy\VirtualProxyInterface;
use Psr\Container\ContainerInterface;
use Yiisoft\Definitions\Contract\DefinitionInterface;
use Yiisoft\Definitions\Helpers\Normalizer;

final class LazyDefinition implements DefinitionInterface
{
public function __construct(
private mixed $definition,
/**
* @psalm-var class-string
*/
private string $class,
) {
}

public function resolve(ContainerInterface $container): VirtualProxyInterface
{
/** @var LazyLoadingValueHolderFactory $factory */
$factory = $container->get(LazyLoadingValueHolderFactory::class);
$definition = $this->definition;

return $factory->createProxy(
$this->class,
static function (mixed &$wrappedObject) use ($container, $definition) {
$definition = Normalizer::normalize($definition);
$wrappedObject = $definition->resolve($container);
return true;
}
);
}
}
1 change: 1 addition & 0 deletions src/ReferencesArray.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ final class ReferencesArray
* @throws InvalidConfigException
*
* @return Reference[]
*
* @psalm-suppress DocblockTypeContradiction
*/
public static function from(array $ids): array
Expand Down
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\Definitions\Tests\Support;

class NotFinalClass
{
private array $arguments;

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

public function getArguments(): array
{
return $this->arguments;
}
}
16 changes: 16 additions & 0 deletions tests/Unit/ArrayDefinitionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use InvalidArgumentException;
use PHPUnit\Framework\TestCase;
use TypeError;
use Yiisoft\Definitions\ArrayDefinition;
use Yiisoft\Definitions\Exception\InvalidConfigException;
use Yiisoft\Definitions\Reference;
Expand Down Expand Up @@ -524,6 +525,21 @@ public function testMagicMethods(): void
);
}

public function testNonArrayMethodArguments(): void
{
$definition = ArrayDefinition::fromConfig([
ArrayDefinition::CLASS_NAME => Mouse::class,
'setNameAndEngine()' => 'kitty',
]);
$container = new SimpleContainer();

$this->expectException(TypeError::class);
$this->expectExceptionMessage(
'Yiisoft\Definitions\ArrayDefinition::resolveFunctionArguments(): Argument #3 ($arguments) must be of type array, string given'
);
$definition->resolve($container);
}

public function testMultipleCall()
{
$definition = ArrayDefinition::fromConfig([
Expand Down
7 changes: 3 additions & 4 deletions tests/Unit/Helpers/DefinitionResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,9 @@ public function testEnsureResolvableScalar(): void
public function testEnsureResolvableDefinition(): void
{
$this->expectException(InvalidConfigException::class);
$this->expectExceptionMessageMatches(
'/^Only references are allowed in constructor arguments, a definition object was provided: (\\\\|)' .
preg_quote(ValueDefinition::class) .
'.*/'
$this->expectExceptionMessage(
'Only references are allowed in constructor arguments, a definition object was provided: ' .
var_export(new ValueDefinition(7), true)
);
DefinitionResolver::ensureResolvable(new ValueDefinition(7));
}
Expand Down
7 changes: 3 additions & 4 deletions tests/Unit/Helpers/DefinitionValidatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -342,10 +342,9 @@ public function testInteger(): void
public function testDefinitionInArguments(): void
{
$this->expectException(InvalidConfigException::class);
$this->expectExceptionMessageMatches(
'/^Only references are allowed in constructor arguments, a definition object was provided: (\\\\|)' .
preg_quote(ValueDefinition::class) .
'.*/'
$this->expectExceptionMessage(
'Only references are allowed in constructor arguments, a definition object was provided: ' .
var_export(new ValueDefinition(56), true)
);
DefinitionValidator::validate([
'class' => GearBox::class,
Expand Down
17 changes: 17 additions & 0 deletions tests/Unit/Helpers/NormalizerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,23 @@ public function testArray(): void
$this->assertSame([], $definition->getMethodsAndProperties());
}

public function testNullClass(): void
{
/** @var ArrayDefinition $definition */
$definition = Normalizer::normalize(
[
'class' => null,
'__construct()' => [42],
],
GearBox::class
);

$this->assertInstanceOf(ArrayDefinition::class, $definition);
$this->assertSame(GearBox::class, $definition->getClass());
$this->assertSame([42], $definition->getConstructorArguments());
$this->assertSame([], $definition->getMethodsAndProperties());
}

public function testReadyObject(): void
{
$container = new SimpleContainer();
Expand Down
65 changes: 65 additions & 0 deletions tests/Unit/LazyDefinitionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Definitions\Tests\Unit;

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

final class LazyDefinitionTest extends TestCase
{
public function testFinalClass(): void
{
$container = new SimpleContainer([
LazyLoadingValueHolderFactory::class => new LazyLoadingValueHolderFactory(),
]);

$class = Phone::class;

$definition = new LazyDefinition([ArrayDefinition::CLASS_NAME => $class], $class);

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

public function testNotFinalClass(): void
{
$container = new SimpleContainer([
LazyLoadingValueHolderFactory::class => new LazyLoadingValueHolderFactory(),
]);

$class = NotFinalClass::class;

$definition = new LazyDefinition([ArrayDefinition::CLASS_NAME => $class], $class);

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

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

public function testInterface(): void
{
$container = new SimpleContainer([
LazyLoadingValueHolderFactory::class => new LazyLoadingValueHolderFactory(),
]);

$class = EngineInterface::class;

$definition = new LazyDefinition([ArrayDefinition::CLASS_NAME => $class], $class);

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

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