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

Extract mappings to their own DTOs #10405

Closed
wants to merge 33 commits into from
Closed

Conversation

greg0ire
Copy link
Member

@greg0ire greg0ire commented Jan 14, 2023

An experiment, not sure if I will manage to do it, but at least it will allow us to port some changes to 2.x:

  • for instance, everywhere FieldMapping the DTO is used, FieldMapping the array-shape should be used
  • we can add missing fields to FieldMapping (for instance, version, or default)

Todo

  • field mapping
  • association mapping
  • embedded classes mapping
  • discriminator column mapping
  • avoid repetition (array access implementation, common fields)
  • use different DTOs for different association types
  • use different DTOs for different sides of the association
  • make classes that should never be instantiated abstract
  • Fix Psalm issues
  • Fix PHPStan issues
  • Implement __sleep()
  • Avoid redundant isCascade* properties

@greg0ire greg0ire marked this pull request as draft January 14, 2023 18:50
@mpdude
Copy link
Contributor

mpdude commented Jan 15, 2023

What is the supposed migration path for this?

In 2.x, the ClassMetadataInfo::$fieldMappings is a public property, marked as READ-ONLY, but not internal. To my understanding, that means it is allowed to read and work with them.

I don't know about the deprecation/transition rules for this project. But changing this on the 3.0 branch means things will break during the upgrade, and there is no "smooth" transition (e. g. by getting deprecation warnings in 2.x, which can be fixed, then the 3.0 upgrade can be made).

I generally support the idea and think it's a good thing design-wise.

Can we make that more user-friendly, by

  • adding the DTO in 2.x already,
  • implementing ArrayAccess, make things look like before
  • trigger a deprecation when the array access is actually used
  • drop the array access in 3.0?

@greg0ire
Copy link
Member Author

I'd actually add the array access on 3.0,much like what I did recently for the Token class in doctrine/lexer, that way the type does not change from array to DTO in a minor. What we might do to ease the transition could be to introduce a factory that would produce arrays with nullable properties instead of optional properties, to make the array closer to the final dto

/** @var int|null The database length of the column. Optional. Default value taken from the type. */
public int|null $length = null;
/**
* @var bool|null Marks the field as the primary key of the entity. Multiple
Copy link
Member Author

Choose a reason for hiding this comment

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

While trying to fix the build, I reverted to bool|null here, to be closer to the previous situation. Now that the build is green, I can do a separate commit to make boolean field not-nullable, and default to false.

@@ -328,15 +328,16 @@ private function getShortName(string $className): string
private function addInheritedFields(ClassMetadata $subClass, ClassMetadata $parentClass): void
{
foreach ($parentClass->fieldMappings as $mapping) {
if (! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
$mapping['inherited'] = $parentClass->name;
$subClassMapping = clone $mapping;
Copy link
Member Author

Choose a reason for hiding this comment

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

Lost a huge amount of time on this, but yeah, we have to clone here now.

Copy link
Contributor

Choose a reason for hiding this comment

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

#10397 changed that area, did you include/merge that already?

why can’t you just update the value?

Copy link
Member Author

Choose a reason for hiding this comment

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

I need to update the child value without updating the parent value. When using an array, a copy is made. When using objects, we're altering the parent objects.

We do need to do a merge up.

Copy link
Contributor

Choose a reason for hiding this comment

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

Would it be better to do the clone up in doLoadMetadata or so, in a more central location?

Copy link
Member Author

Choose a reason for hiding this comment

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

Merge up done in #10421

About doLoadMetadata, I'm not sure… I mean there's one clone per mapping to do, so it's not like you could pass clones to addInheritedFields or something 🤔

@greg0ire
Copy link
Member Author

greg0ire commented Jan 18, 2023

Did a new push, comes with static analysis issues that I should be able to solve once I have converted every argument to addMappingInheritanceInformation to a DTO.

@greg0ire greg0ire changed the title Extract FieldMapping in its own DTO Extract FieldMapping and AssociationMapping to their own DTO Jan 21, 2023
@greg0ire
Copy link
Member Author

Pushed a new version with an association mapping DTO, hopefully that was the hardest part of the job.

@greg0ire
Copy link
Member Author

greg0ire commented Jan 28, 2023

Just found out that I'm doing the opposite of what's been done 13 years ago in 8d3e0e6 😅
Why oh why?

@mpdude
Copy link
Contributor

mpdude commented Jan 28, 2023

Maybe performance? Arrays might be faster to access than methods to call?

@greg0ire
Copy link
Member Author

greg0ire commented Jan 28, 2023

Discussed it internally, and you are right… well, you were. It was true in PHP 5.3, but no longer is. I think I can proceed with this.

@mpdude
Copy link
Contributor

mpdude commented Jan 28, 2023

Before you put too much work into it, are you sure there is a smooth migration path?

@greg0ire
Copy link
Member Author

I think the ArrayAccess implementation is enough. All the arrays I'm changing are object-like arrays, so they are very unlikely to be used with anything else than the [] notation. Also, I experimented with this on doctrine/lexer and got no complaints.

@greg0ire greg0ire changed the title Extract FieldMapping and AssociationMapping to their own DTO Extract mappings to their own DTOs Feb 5, 2023
Now that we deal with objects, everything is simpler.
@greg0ire greg0ire requested a review from beberlei March 28, 2023 11:32
When switching to an object API, it becomes obvious that it should be
mandatory. You have to assert it is not null everywhere.
Copy link
Member

@SenseException SenseException left a comment

Choose a reason for hiding this comment

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

I haven't done the full review yet. The amount of changes slows my progress, so maybe I'll do it in parts.

@@ -157,7 +158,7 @@ public function evictCollectionRegions(): void

foreach ($metadatas as $metadata) {
foreach ($metadata->associationMappings as $association) {
if (! $association['type'] & ClassMetadata::TO_MANY) {
if (! $association instanceof ToManyAssociationMapping) {
Copy link
Member

Choose a reason for hiding this comment

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

If those are all AssociationMapping, wouldn't the use of a method be an option instead of an instanceof check? You've used methods at other places too.

Copy link
Member Author

Choose a reason for hiding this comment

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

You're right, I will add such a method.

@greg0ire
Copy link
Member Author

Closing in favor of smaller PRs, the first of which will be #10607

@greg0ire greg0ire closed this Mar 31, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants