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

Split Instantiator #395

Draft
wants to merge 3 commits into
base: 1.x
Choose a base branch
from
Draft

Split Instantiator #395

wants to merge 3 commits into from

Conversation

kbond
Copy link
Member

@kbond kbond commented Jan 10, 2023

Closes #388.

This PR splits the Instantator into 2 separate objects:

  • Instantiator: now only create the object (using constructor/no constructor/callback/named constructor)
  • Hydrator: takes the instantiated object and hydrates it with the attributes not used to instantiate

The following is now possible:

// customize the default instantiator (defined in your bundle config)
$factory->instantiateWith(Instantiator::noConstructor()); // trigger to create w/o constructor

$factory->instantiateWithoutConstructor(); // shortcut for above

$factory->instantiateWith('factoryMethod'); // creates via Entity::factoryMethod(...)

$factory->instantiateWith([SomeCustomInstantiator::class, 'method']);

$factory->instantiateWith(function(array $attributes) {
   return new ...;
});

// customize the default hydrator (defined in your bundle config)
$factory->hydrateWith(Hydrator::ALLOW_EXTRA_ATTRIBUTES);

$factory->hydrateWith(Hydrator::ALLOW_EXTRA_ATTRIBUTES|Hydrator::ALWAYS_FORCE_PROPERTIES);

$factory->hydrateWith(fn(Hydrator $h) => $h->alwaysForceProperties(['foo', 'bar']));

// fully customize
$factory->hydrateWith(function(object $object, array $attributes) {
    // ...

    return $object;
});

Note: if using a closure or non-Instantiator callable for the instantiator, the hydrator isn't used. This is to avoid the unset issue discussed here. I think this is better for DX (not requiring you create a custom instantiator and hydrator) but might cause problems when trying to solve the cascade: persist problem in #312.

Todo:

  • Deprectations layer
  • Tests
  • Docs

@kbond kbond marked this pull request as draft January 10, 2023 22:27
@kbond
Copy link
Member Author

kbond commented Jan 10, 2023

@nikophil, could you give this an early, high-level review?

@kbond kbond changed the title Split Instantiator up Split Instantiator Jan 10, 2023
Comment on lines +116 to +118
if (!$hydrator instanceof Hydrator) {
$hydrator = (new Hydrator())->using($hydrator);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is actually a nice technique 👍

{
$instantiator = $this->instantiator ?? self::configuration()->instantiator();

if (!$instantiator instanceof Instantiator && !$this->hydrator) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: if using a closure or non-Instantiator callable for the instantiator, the hydrator isn't used.

shouldn't we throw an error if we detect an hydrator which is not the default hydrator in this case?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps but then we'd break the possibility of fixing cascade persist with custom instantiators. One problem at a time though. I'll throw an exception for now.

Copy link
Member

@nikophil nikophil Jan 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

damn, that's quite a complex problem 🤯

@kbond kbond mentioned this pull request Apr 17, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

Handling factory methods using instantiateWith
2 participants