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

Improve the TypeInfo docs #20014

Closed
javiereguiluz opened this issue Jul 2, 2024 · 2 comments
Closed

Improve the TypeInfo docs #20014

javiereguiluz opened this issue Jul 2, 2024 · 2 comments
Labels
Milestone

Comments

@javiereguiluz
Copy link
Member

In #19554 we merged the contribution that @Korbeil made to document the new TypeInfo component.

After merging it, I have some questions about it:


(1) When/how do you use the feature to build types? We show examples like these:

use Symfony\Component\TypeInfo\Type;

Type::int();
Type::nullable(Type::string());
Type::generic(Type::object(Collection::class), Type::int());

I can't understand how would you use that in a real PHP application. Can anyone show a real example? Thanks!


(2) In the second example, we show how to do $typeResolver = TypeResolver::create(); to get type information from an existing PHP class. But, we don't show any PHP class, so the examples feel a bit abstract to me.

Would anyone please volunteer to provide a good PHP class example that matches those code examples? Thanks!


(3) This component also supports "raw string resolving", but it's lacking a good example of the PHP class with those PHPDoc contents and the needed code to get the type information. Thanks!

@javiereguiluz javiereguiluz added this to the 7.1 milestone Jul 2, 2024
@Korbeil
Copy link
Contributor

Korbeil commented Jul 3, 2024

To answer your questions:

This is not a component you will use in a Symfony app (1). This is a component made for other components or for libraries to use. For example it would be used within PropertyInfo, Serializer or some external libraries like jolicode/automapper. But I don't see a usage in a web PHP application.

For all the cases I listed, this will be used to describe metadata about PHP classes within theses libraries. Let's take the Symfony's Serializer as an example:

readonly class UserValueObject
{
  public function(
    public string $name,
    public int $age,
  ) {
  }
}

$serializer = new Serializer(...); // coming from DI
$object = $serializer->deserialize($request->getContent(), UserValueObject::class, 'json');

In this case you want to deserialize a request body into a given UserValueObject. To make this happen, the Serializer will convert json to array format (decoding part of the Serializer) then will transform array to UserValueObject thanks to denormalization. During that denormalization we will use the ObjectNormalizer witch needs to gather metadata about properties within the class it is denormalizing.
Today we do it thanks to PropertyInfo PropertyTypeExtractorInterface:

interface PropertyTypeExtractorInterface
{
    /**
     * Gets types of a property.
     *
     * @return Type[]|null
     */
    public function getTypes(string $class, string $property, array $context = []);
}

There is some drawbacks about this method (which we covered in a talk Mathias and I gave in recent Symfony event: https://live.symfony.com/account/replay/video/977) and this is to improve this metadata we created TypeInfo.
TypeInfo makes it possible to handle more complex types (in opposition to PropertyInfo actual extractors) so libraries like Serializer can have more rich metadata.

I'm not sure we can provide a "good PHP class example" (2) like you said because of what I explained earlier, this is not something designed to be used by everybody and made for internals mostly.

About "raw string resolving" (3) we need a bit more code to have a working example, let's make a simple ValueObject:

readonly class UserValueObject
{
  /**
   * @param string[] $addresses
   */
  public function(
    public string $name,
    public array $addresses,
  ) {
  }
}

Then we extract the phpDoc we want to parse:

$reflectionClass = new \ReflectionClass(UserValueObject::class);
$reflectionConstructor = $reflectionClass->getConstructor();
$rawDocNode = $reflectionConstructor->getDocComment();

// all of theses classes are coming from `phpstan/phpdoc` library
$phpDocParser = new PhpDocParser(new TypeParser(new ConstExprParser()), new ConstExprParser());
$tokens = new TokenIterator($this->lexer->tokenize($rawDocNode));
$phpDocNode = $this->phpDocParser->parse($tokens);
$phpDocNode = $tokens->consumeTokenType(Lexer::TOKEN_END);
$phpDocParam = $phpDocNode->getTagsByName('@param');

The previous code was taken from PhpStanExtractor that is within the PropertyInfo component.

And we pass it to the TypeResolver within TypeInfo so it can tell us what this phpDoc is about:

$typeResolver = TypeResolver::create();
dd($typeResolver->resolve($phpDocParam->value));
// will print:
// ^ Symfony\Component\TypeInfo\Type\CollectionType^ {#2435
//  -type: Symfony\Component\TypeInfo\Type\BuiltinType^ {#2436
//    -typeIdentifier: Symfony\Component\TypeInfo\TypeIdentifier^ {#505
//      +name: "STRING"
//      +value: "string"
//    }
//  }
//  -isList: false
// }

Hope this answered all your questions @javiereguiluz, please ask me if you miss any details.

javiereguiluz added a commit that referenced this issue Dec 10, 2024
…orbeil)

This PR was merged into the 7.2 branch.

Discussion
----------

[TypeInfo] Add more details to TypeInfo documentation

This pull request is to revamp current TypeInfo documentation.
I tried to make the most of the recent changes while answering `@javiereguiluz`'s issue (thanks to "PHPDoc parsing" part).

It should fixes #20389, #20064 and #20014.

Commits
-------

dc999f3 Add more details to TypeInfo documentation
@javiereguiluz
Copy link
Member Author

Closing as fixed in #20407. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants