Skip to content

Commit

Permalink
refactor: add BC layer for methods in Instantiator (#535)
Browse files Browse the repository at this point in the history
  • Loading branch information
nikophil authored Dec 14, 2023
1 parent 73cd6a9 commit 531b30f
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 30 deletions.
5 changes: 0 additions & 5 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@ parameters:
count: 1
path: src/AnonymousFactoryGenerator.php

-
message: "#^Parameter \\#1 \\$objectOrClass of class ReflectionClass constructor expects class\\-string\\<T of object\\>\\|T of object, string\\|null given\\.$#"
count: 1
path: src/Bundle/DependencyInjection/GlobalStatePass.php

-
message: "#^Parameter \\#1 \\$class of method Doctrine\\\\Persistence\\\\ManagerRegistry\\:\\:getManagerForClass\\(\\) expects class\\-string, string given\\.$#"
count: 1
Expand Down
2 changes: 1 addition & 1 deletion src/Bundle/DependencyInjection/GlobalStatePass.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ private function isInvokableService(ContainerBuilder $container, string $globalS

$globalStateItemDefinition = $container->getDefinition($globalStateItem);

return (new \ReflectionClass($globalStateItemDefinition->getClass()))->hasMethod('__invoke');
return (new \ReflectionClass($globalStateItemDefinition->getClass()))->hasMethod('__invoke'); // @phpstan-ignore-line
}

private function isStandaloneStory(ContainerBuilder $container, string $globalStateItem): bool
Expand Down
4 changes: 2 additions & 2 deletions src/Bundle/DependencyInjection/ZenstruckFoundryExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,11 @@ private function configureDefaultInstantiator(array $config, ContainerBuilder $c
$definition->setFactory([Instantiator::class, $withoutConstructor ? 'withoutConstructor' : 'withConstructor']);

if ($config['allow_extra_attributes']) {
$definition->addMethodCall('allowExtraAttributes');
$definition->addMethodCall('allowExtra');
}

if ($config['always_force_properties']) {
$definition->addMethodCall('alwaysForceProperties');
$definition->addMethodCall('alwaysForce');
}
}

Expand Down
36 changes: 32 additions & 4 deletions src/Instantiator.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public function __invoke(array $attributes, string $class): object

foreach ($attributes as $attribute => $value) {
if (0 === \mb_strpos($attribute, 'optional:')) {
trigger_deprecation('zenstruck\foundry', '1.5.0', 'Using "optional:" attribute prefixes is deprecated, use Instantiator::allowExtraAttributes() instead (https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#instantiation).');
trigger_deprecation('zenstruck\foundry', '1.5.0', 'Using "optional:" attribute prefixes is deprecated, use Instantiator::allowExtra() instead (https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#instantiation).');
continue;
}

Expand All @@ -75,7 +75,7 @@ public function __invoke(array $attributes, string $class): object
}

if (0 === \mb_strpos($attribute, 'force:')) {
trigger_deprecation('zenstruck\foundry', '1.5.0', 'Using "force:" property prefixes is deprecated, use Instantiator::alwaysForceProperties() instead (https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#instantiation).');
trigger_deprecation('zenstruck\foundry', '1.5.0', 'Using "force:" property prefixes is deprecated, use Instantiator::alwaysForce() instead (https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#instantiation).');

self::forceSet($object, \mb_substr($attribute, 6), $value);

Expand Down Expand Up @@ -135,14 +135,28 @@ public static function withConstructor(): self
* Ignore attributes that can't be set to object.
*
* @param string[] $attributes The attributes you'd like the instantiator to ignore (if empty, ignore any extra)
*
* @deprecated Use self::allowExtra() instead
*/
public function allowExtraAttributes(array $attributes = []): self
{
if (empty($attributes)) {
trigger_deprecation('zenstruck/foundry', '1.37.0', 'Method "Instantiator::allowExtraAttributes()" is deprecated. Please use "Instantiator::allowExtra()" instead.');

return $this->allowExtra(...$attributes);
}

/**
* Ignore attributes that can't be set to object.
*
* @param string $parameters The attributes you'd like the instantiator to ignore (if empty, ignore any extra)
*/
public function allowExtra(string ...$parameters): self
{
if (empty($parameters)) {
$this->allowExtraAttributes = true;
}

$this->extraAttributes = $attributes;
$this->extraAttributes = $parameters;

return $this;
}
Expand All @@ -151,8 +165,22 @@ public function allowExtraAttributes(array $attributes = []): self
* Always force properties, never use setters (still uses constructor unless disabled).
*
* @param string[] $properties The properties you'd like the instantiator to "force set" (if empty, force set all)
*
* @deprecated Use self::alwaysForce() instead
*/
public function alwaysForceProperties(array $properties = []): self
{
trigger_deprecation('zenstruck/foundry', '1.37.0', 'Method "Instantiator::alwaysForceProperties()" is deprecated. Please use "Instantiator::alwaysForce()" instead.');

return $this->alwaysForce(...$properties);
}

/**
* Always force properties, never use setters (still uses constructor unless disabled).
*
* @param string $properties The properties you'd like the instantiator to "force set" (if empty, force set all)
*/
public function alwaysForce(string ...$properties): self
{
if (empty($properties)) {
$this->alwaysForceProperties = true;
Expand Down
2 changes: 1 addition & 1 deletion tests/Fixtures/Factories/CategoryFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ protected function initialize(): static
{
return $this
->instantiateWith(
Instantiator::withConstructor()->allowExtraAttributes(['extraPostsBeforeInstantiate', 'extraPostsAfterInstantiate'])
Instantiator::withConstructor()->allowExtra('extraPostsBeforeInstantiate', 'extraPostsAfterInstantiate')
)
->beforeInstantiate(function(array $attributes): array {
if (isset($attributes['extraPostsBeforeInstantiate'])) {
Expand Down
2 changes: 1 addition & 1 deletion tests/Fixtures/Factories/PostFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ protected function initialize(): static
{
return $this
->instantiateWith(
Instantiator::withConstructor()->allowExtraAttributes(['extraCategoryBeforeInstantiate', 'extraCategoryAfterInstantiate'])
Instantiator::withConstructor()->allowExtra('extraCategoryBeforeInstantiate', 'extraCategoryAfterInstantiate')
)
->beforeInstantiate(function(array $attributes): array {
if (isset($attributes['extraCategoryBeforeInstantiate'])) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ public function custom_instantiator_config(): void
],
]);

$this->assertContainerBuilderHasServiceDefinitionWithMethodCall('.zenstruck_foundry.default_instantiator', 'allowExtraAttributes');
$this->assertContainerBuilderHasServiceDefinitionWithMethodCall('.zenstruck_foundry.default_instantiator', 'alwaysForceProperties');
$this->assertContainerBuilderHasServiceDefinitionWithMethodCall('.zenstruck_foundry.default_instantiator', 'allowExtra');
$this->assertContainerBuilderHasServiceDefinitionWithMethodCall('.zenstruck_foundry.default_instantiator', 'alwaysForce');

$instantiator = $this->container->get('.zenstruck_foundry.default_instantiator');

Expand Down
91 changes: 77 additions & 14 deletions tests/Unit/InstantiatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,9 @@ public function extra_attributes_throws_exception(): void

/**
* @test
* @group legacy
*/
public function can_set_attributes_that_should_be_optional(): void
public function can_set_attributes_that_should_be_optional_legacy(): void
{
$object = Instantiator::withConstructor()->allowExtraAttributes(['extra'])([
'propB' => 'B',
Expand All @@ -175,6 +176,33 @@ public function can_set_attributes_that_should_be_optional(): void
$this->assertSame('constructor B', $object->getPropB());
}

/**
* @test
* @group legacy
*/
public function can_always_allow_extra_attributes_legacy(): void
{
$object = Instantiator::withConstructor()->allowExtraAttributes()([
'propB' => 'B',
'extra' => 'foo',
], InstantiatorDummy::class);

$this->assertSame('constructor B', $object->getPropB());
}

/**
* @test
*/
public function can_set_attributes_that_should_be_optional(): void
{
$object = Instantiator::withConstructor()->allowExtra('extra')([
'propB' => 'B',
'extra' => 'foo',
], InstantiatorDummy::class);

$this->assertSame('constructor B', $object->getPropB());
}

/**
* @test
*/
Expand All @@ -183,7 +211,7 @@ public function extra_attributes_not_defined_throws_exception(): void
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Cannot set attribute "extra2" for object "Zenstruck\Foundry\Tests\Unit\InstantiatorDummy" (not public and no setter).');

Instantiator::withConstructor()->allowExtraAttributes(['extra1'])([
Instantiator::withConstructor()->allowExtra('extra1')([
'propB' => 'B',
'extra1' => 'foo',
'extra2' => 'bar',
Expand All @@ -196,7 +224,7 @@ public function extra_attributes_not_defined_throws_exception(): void
*/
public function can_prefix_extra_attribute_key_with_optional_to_avoid_exception(): void
{
$this->expectDeprecation('Since zenstruck\foundry 1.5.0: Using "optional:" attribute prefixes is deprecated, use Instantiator::allowExtraAttributes() instead (https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#instantiation).');
$this->expectDeprecation('Since zenstruck\foundry 1.5.0: Using "optional:" attribute prefixes is deprecated, use Instantiator::allowExtra() instead (https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#instantiation).');

$object = Instantiator::withConstructor()([
'propB' => 'B',
Expand All @@ -211,7 +239,7 @@ public function can_prefix_extra_attribute_key_with_optional_to_avoid_exception(
*/
public function can_always_allow_extra_attributes(): void
{
$object = Instantiator::withConstructor()->allowExtraAttributes()([
$object = Instantiator::withConstructor()->allowExtra()([
'propB' => 'B',
'extra' => 'foo',
], InstantiatorDummy::class);
Expand Down Expand Up @@ -240,8 +268,9 @@ public function can_disable_constructor(): void

/**
* @test
* @group legacy
*/
public function can_set_attributes_that_should_be_force_set(): void
public function can_set_attributes_that_should_be_force_set_legacy(): void
{
$object = Instantiator::withoutConstructor()->alwaysForceProperties(['propD'])([
'propB' => 'B',
Expand All @@ -252,6 +281,20 @@ public function can_set_attributes_that_should_be_force_set(): void
$this->assertSame('D', $object->getPropD());
}

/**
* @test
*/
public function can_set_attributes_that_should_be_force_set(): void
{
$object = Instantiator::withoutConstructor()->alwaysForce('propD')([
'propB' => 'B',
'propD' => 'D',
], InstantiatorDummy::class);

$this->assertSame('setter B', $object->getPropB());
$this->assertSame('D', $object->getPropD());
}

/**
* @test
* @group legacy
Expand All @@ -278,7 +321,7 @@ public function can_disable_constructor_legacy(): void
*/
public function prefixing_attribute_key_with_force_sets_the_property_directly(): void
{
$this->expectDeprecation('Since zenstruck\foundry 1.5.0: Using "force:" property prefixes is deprecated, use Instantiator::alwaysForceProperties() instead (https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#instantiation).');
$this->expectDeprecation('Since zenstruck\foundry 1.5.0: Using "force:" property prefixes is deprecated, use Instantiator::alwaysForce() instead (https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#instantiation).');

$object = Instantiator::withConstructor()([
'propA' => 'A',
Expand All @@ -300,7 +343,7 @@ public function prefixing_attribute_key_with_force_sets_the_property_directly():
*/
public function prefixing_snake_case_attribute_key_with_force_sets_the_property_directly(): void
{
$this->expectDeprecation('Since zenstruck\foundry 1.5.0: Using "force:" property prefixes is deprecated, use Instantiator::alwaysForceProperties() instead (https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#instantiation).');
$this->expectDeprecation('Since zenstruck\foundry 1.5.0: Using "force:" property prefixes is deprecated, use Instantiator::alwaysForce() instead (https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#instantiation).');

$object = Instantiator::withConstructor()([
'prop_a' => 'A',
Expand All @@ -322,7 +365,7 @@ public function prefixing_snake_case_attribute_key_with_force_sets_the_property_
*/
public function prefixing_kebab_case_attribute_key_with_force_sets_the_property_directly(): void
{
$this->expectDeprecation('Since zenstruck\foundry 1.5.0: Using "force:" property prefixes is deprecated, use Instantiator::alwaysForceProperties() instead (https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#instantiation).');
$this->expectDeprecation('Since zenstruck\foundry 1.5.0: Using "force:" property prefixes is deprecated, use Instantiator::alwaysForce() instead (https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#instantiation).');

$object = Instantiator::withConstructor()([
'prop-a' => 'A',
Expand All @@ -344,7 +387,7 @@ public function prefixing_kebab_case_attribute_key_with_force_sets_the_property_
*/
public function prefixing_invalid_attribute_key_with_force_throws_exception(): void
{
$this->expectDeprecation('Since zenstruck\foundry 1.5.0: Using "force:" property prefixes is deprecated, use Instantiator::alwaysForceProperties() instead (https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#instantiation).');
$this->expectDeprecation('Since zenstruck\foundry 1.5.0: Using "force:" property prefixes is deprecated, use Instantiator::alwaysForce() instead (https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#instantiation).');
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Class "Zenstruck\Foundry\Tests\Unit\InstantiatorDummy" does not have property "extra".');

Expand Down Expand Up @@ -425,8 +468,9 @@ public function force_get_throws_exception_for_invalid_property(): void

/**
* @test
* @group legacy
*/
public function can_use_always_force_mode(): void
public function can_use_always_force_mode_legacy(): void
{
$object = Instantiator::withConstructor()->alwaysForceProperties()([
'propA' => 'A',
Expand All @@ -442,6 +486,25 @@ public function can_use_always_force_mode(): void
$this->assertSame('D', $object->getPropD());
}

/**
* @test
*/
public function can_use_always_force_mode(): void
{
$object = Instantiator::withConstructor()->alwaysForce()([
'propA' => 'A',
'propB' => 'B',
'propC' => 'C',
'propD' => 'D',
], InstantiatorDummy::class);

$this->assertSame('A', $object->propA);
$this->assertSame('A', $object->getPropA());
$this->assertSame('constructor B', $object->getPropB());
$this->assertSame('constructor C', $object->getPropC());
$this->assertSame('D', $object->getPropD());
}

/**
* @test
* @group legacy
Expand Down Expand Up @@ -494,7 +557,7 @@ public function always_force_mode_throws_exception_for_extra_attributes(): void
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Class "Zenstruck\Foundry\Tests\Unit\InstantiatorDummy" does not have property "extra".');

Instantiator::withConstructor()->alwaysForceProperties()([
Instantiator::withConstructor()->alwaysForce()([
'propB' => 'B',
'extra' => 'foo',
], InstantiatorDummy::class);
Expand Down Expand Up @@ -522,7 +585,7 @@ public function always_force_mode_allows_optional_attribute_name_prefix(): void
*/
public function always_force_mode_with_allow_extra_attributes_mode(): void
{
$object = Instantiator::withConstructor()->allowExtraAttributes()->alwaysForceProperties()([
$object = Instantiator::withConstructor()->allowExtra()->alwaysForce()([
'propB' => 'B',
'propD' => 'D',
'extra' => 'foo',
Expand All @@ -536,7 +599,7 @@ public function always_force_mode_with_allow_extra_attributes_mode(): void
*/
public function always_force_mode_can_set_parent_class_properties(): void
{
$object = Instantiator::withConstructor()->alwaysForceProperties()([
$object = Instantiator::withConstructor()->alwaysForce()([
'propA' => 'A',
'propB' => 'B',
'propC' => 'C',
Expand All @@ -559,7 +622,7 @@ public function invalid_attribute_type_with_allow_extra_enabled_throws_exception
{
$this->expectException(\Throwable::class);

Instantiator::withConstructor()->allowExtraAttributes()([
Instantiator::withConstructor()->allowExtra()([
'propB' => 'B',
'propF' => 'F',
], InstantiatorDummy::class);
Expand Down

0 comments on commit 531b30f

Please sign in to comment.