diff --git a/src/Bundle/DependencyInjection/ZenstruckFoundryExtension.php b/src/Bundle/DependencyInjection/ZenstruckFoundryExtension.php index aa842b0e2..1e491b552 100644 --- a/src/Bundle/DependencyInjection/ZenstruckFoundryExtension.php +++ b/src/Bundle/DependencyInjection/ZenstruckFoundryExtension.php @@ -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'); } } diff --git a/src/Instantiator.php b/src/Instantiator.php index f1887269b..d005c158b 100644 --- a/src/Instantiator.php +++ b/src/Instantiator.php @@ -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; } @@ -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); @@ -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; } @@ -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; diff --git a/tests/Fixtures/Factories/CategoryFactory.php b/tests/Fixtures/Factories/CategoryFactory.php index d643c4a57..c2aebdb68 100644 --- a/tests/Fixtures/Factories/CategoryFactory.php +++ b/tests/Fixtures/Factories/CategoryFactory.php @@ -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'])) { diff --git a/tests/Fixtures/Factories/PostFactory.php b/tests/Fixtures/Factories/PostFactory.php index 99b71bda7..9f281b4b4 100644 --- a/tests/Fixtures/Factories/PostFactory.php +++ b/tests/Fixtures/Factories/PostFactory.php @@ -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'])) { diff --git a/tests/Unit/InstantiatorTest.php b/tests/Unit/InstantiatorTest.php index f4b559246..9b4777ba3 100644 --- a/tests/Unit/InstantiatorTest.php +++ b/tests/Unit/InstantiatorTest.php @@ -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', @@ -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 */ @@ -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', @@ -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', @@ -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); @@ -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', @@ -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 @@ -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', @@ -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', @@ -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', @@ -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".'); @@ -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', @@ -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 @@ -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); @@ -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', @@ -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', @@ -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);