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

Describe iterable type arrays #2314

Merged
merged 2 commits into from
Jun 1, 2021

Conversation

franmomu
Copy link
Contributor

@franmomu franmomu commented May 23, 2021

Q A
Type improvement
BC Break no
Fixed issues

Summary

This describes better every array type in ClassMetadata.

In the FieldMapping psalm type, I've put together all the options I've seen (maybe there are more), the good thing about creating a type is that we can reuse it in more places (like UnitOfWork which some of its methods receive an array $mapping).

@@ -57,6 +57,43 @@
* get the whole class name, namespace inclusive, prepended to every property in
* the serialized representation).
*
* @psalm-type FieldMapping = array{
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've used this psalm type to define the property fieldMappings and also as argument for some methods. Maybe this is not totally accurated since for fieldMappings I guess there are more mandatory keys than type, but I think for now is fine.

We could maybe create a FieldMappingParameter with all the optional keys and then FieldMapping restricting the mandatory ones, something like this:

/**
 * @psalm-type FieldMappingParameter = array{
 *     type: string, 
 *     fieldName?: string, 
 *     name?: string, 
 *     strategy?: string, 
 *     ...
 * }
 * @psalm-type FieldMapping = FieldMappingParameter&array{
 *     fieldName: string, 
 *     name: string
 * }
*/

@franmomu franmomu force-pushed the describe_iterables_classmetadata branch from 9245f87 to 35e00c1 Compare May 24, 2021 13:07
@franmomu franmomu closed this May 26, 2021
@franmomu franmomu reopened this May 26, 2021
Copy link
Member

@alcaeus alcaeus left a comment

Choose a reason for hiding this comment

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

Wow, this is cool stuff! I've left some questions below.

As for required and optional keys in the field mapping, there are most likely more required fields other than type, but I'd have to go through this myself to figure that out. I can do so once you're done making changes, but if you feel brave, I'll gladly let you figure out what the code assumes to be there ;)

@@ -260,14 +299,16 @@
/**
* READ-ONLY: The array of indexes for the document collection.
*
* @var array
* @var array<array<string, mixed>>
* @psalm-var array<array{keys: array<string, mixed>, options: array<string, mixed>}>
Copy link
Member

Choose a reason for hiding this comment

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

I'm wondering if we should define types for this. Consider:

Suggested change
* @psalm-var array<array{keys: array<string, mixed>, options: array<string, mixed>}>
* @psalm-var array<IndexMapping>

Defining an IndexMapping psalm type elsewhere that makes use of other types (e.g. IndexKeys and IndexOptions) would make for easier reading and understanding of what is actually stored.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea! Done, I've defined them in ClassMetadata, but I guess maybe should belong somewhere else.

lib/Doctrine/ODM/MongoDB/Mapping/ClassMetadata.php Outdated Show resolved Hide resolved
lib/Doctrine/ODM/MongoDB/Mapping/ClassMetadata.php Outdated Show resolved Hide resolved
@franmomu franmomu force-pushed the describe_iterables_classmetadata branch from 35e00c1 to d3e00f8 Compare May 27, 2021 21:57
Comment on lines +92 to +102
* @psalm-type FieldMapping = array{
* type: string,
* fieldName: string,
* name: string,
* isCascadeRemove: bool,
* isCascadePersist: bool,
* isCascadeRefresh: bool,
* isCascadeMerge: bool,
* isCascadeDetach: bool,
* isOwningSide: bool,
* isInverseSide: bool,
Copy link
Contributor Author

@franmomu franmomu May 27, 2021

Choose a reason for hiding this comment

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

This is how far I've arrived, I had to repeat the keys as defining them as intersection of FielMappingConfig&{mandatory_field: type} doesn't seem to work properly.

I've copied the mandatory keys at the beginning of the definitions.

Copy link
Member

@alcaeus alcaeus left a comment

Choose a reason for hiding this comment

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

I left a note on the type, but I believe that what we have here is an improvement worth merging already. I was wanting to experiment with Psalm types a little more, so that will be a nice exercise when refactoring the Metadata class as alluded to in another PR.

Comment on lines +62 to +63
* fieldName?: string,
* name?: string,
Copy link
Member

Choose a reason for hiding this comment

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

Looking at this, I believe we need two types:

  • The FieldMapping type: this type defines how we store the field metadata internally
  • The FieldMappingConfig type: this type defines what users can pass to the mapField method.

For example, the mapField method requires either fieldName or name property to be given, but once the mapping is stored internally, both fields will be set. Having them optional in the internal type requires more type checks than necessary, hence the suggestion to define separate types.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, this is how is done, mapField is defined like:

/**     
 * Map a field.     
 *     
 * @psalm-param FieldMappingConfig $mapping     
 *     
 * @psalm-return FieldMapping     
 */

@alcaeus alcaeus self-assigned this May 31, 2021
@alcaeus alcaeus added this to the 2.3.0 milestone May 31, 2021
@alcaeus
Copy link
Member

alcaeus commented May 31, 2021

@franmomu can you rebase to resolve the conflicts?

@alcaeus alcaeus enabled auto-merge (squash) May 31, 2021 11:15
auto-merge was automatically disabled May 31, 2021 12:08

Head branch was pushed to by a user without write access

@franmomu franmomu force-pushed the describe_iterables_classmetadata branch from d3e00f8 to bd5bca1 Compare May 31, 2021 12:08
@franmomu franmomu closed this May 31, 2021
@franmomu franmomu reopened this May 31, 2021
@franmomu franmomu force-pushed the describe_iterables_classmetadata branch from bd5bca1 to 08f0d4c Compare June 1, 2021 06:44
@@ -57,6 +57,128 @@
* get the whole class name, namespace inclusive, prepended to every property in
* the serialized representation).
*
* @psalm-type FieldMappingConfig = array{
* type?: string,
Copy link
Contributor Author

@franmomu franmomu Jun 1, 2021

Choose a reason for hiding this comment

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

I had to make type also optional in FieldMappingConfig because these methods

public function mapOneEmbedded(array $mapping): void
{
$mapping['embedded'] = true;
$mapping['type'] = 'one';
$this->mapField($mapping);
}

do not require type.

@alcaeus alcaeus merged commit 07ff1ea into doctrine:2.3.x Jun 1, 2021
@alcaeus
Copy link
Member

alcaeus commented Jun 1, 2021

Thanks @franmomu!

@franmomu franmomu deleted the describe_iterables_classmetadata branch June 1, 2021 09:37
@alcaeus alcaeus modified the milestones: 2.3.0-alpha1, 2.3.0 Sep 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants