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

refactor: add BC layer for methods in Instantiator #535

Merged
merged 1 commit into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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