Skip to content

[PropertyInfo] Import the component #15858

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

Closed
wants to merge 4 commits into from
Closed

Conversation

dunglas
Copy link
Member

@dunglas dunglas commented Sep 21, 2015

Q A
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets n/a
License MIT
Doc PR symfony/symfony-docs#5717

As discussed with @fabpot (see #14844), this PR moves dunglas/php-property-info under the Symfony umbrella.

Rationale behind this new component (extracted from README.md):

PHP doesn't support explicit type definition. This is annoying, especially when doing meta programming.
Various libraries including but not limited to Doctrine ORM and the Symfony Validator provide their own type managing
system.
This library extracts various information including the type and documentation from PHP class property from metadata of popular sources:

  • Setter method with type hint
  • PHPDoc DocBlock
  • Doctrine ORM mapping (annotation, XML, YML or custom format)
  • PHP 7 scalar typehint and return type
  • Serializer metadata

Usage:

<?php

// Use Composer autoload
require 'vendor/autoload.php';

use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Tools\Setup;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\Id;
use Symfony\Component\PropertyInfo\Extractors\DoctrineExtractor;
use Symfony\Component\PropertyInfo\Extractors\PhpDocExtractor;
use Symfony\Component\PropertyInfo\Extractors\ReflectionExtractor;
use Symfony\Component\PropertyInfo\PropertyInfo;

/**
 * @Entity
 */
class MyTestClass
{
    /**
     * @Id
     * @Column(type="integer")
     */
    public $id;
    /**
     * This is a date (short description).
     *
     * With a long description.
     *
     * @var \DateTime
     */
    public $foo;
    private $bar;

    public function setBar(\SplFileInfo $bar)
    {
        $this->bar = $bar;
    }
}

// Doctrine initialization (necessary only to use the Doctrine Extractor)
$config = Setup::createAnnotationMetadataConfiguration([__DIR__], true);
$entityManager = EntityManager::create([
    'driver' => 'pdo_sqlite',
    // ...
], $config);

$doctrineExtractor = new DoctrineExtractor($entityManager->getMetadataFactory());
$phpDocExtractor = new PhpDocExtractor();
$reflectionExtractor = new ReflectionExtractor();

$propertyInfo = new PropertyInfo(
    array($reflectionExtractor),
    array($doctrineExtractor, $phpDocExtractor, $reflectionExtractor),
    array($phpDocExtractor),
    array($reflectionExtractor)
);

var_dump($propertyInfo->getProperties('MyTestClass'));
var_dump($propertyInfo->getTypes('MyTestClass', 'foo'));
var_dump($propertyInfo->getTypes('MyTestClass', 'id'));
var_dump($propertyInfo->getTypes('MyTestClass', 'bar'));
var_dump($propertyInfo->isReadable('MyTestClass', 'id'));
var_dump($propertyInfo->isReadable('MyTestClass', 'bar'));
var_dump($propertyInfo->isWritable('MyTestClass', 'foo'));
var_dump($propertyInfo->isWritable('MyTestClass', 'bar'));
var_dump($propertyInfo->getShortDescription('MyTestClass', 'foo'));
var_dump($propertyInfo->getLongDescription('MyTestClass', 'foo'));

Output:

array(3) {
  [0] =>
  string(2) "id"
  [1] =>
  string(3) "foo"
  [2] =>
  string(3) "Bar"
}
array(1) {
  [0] =>
  class Symfony\Component\PropertyInfo\Type#36 (6) {
    private $builtinType =>
    string(6) "object"
    private $nullable =>
    bool(false)
    private $class =>
    string(8) "DateTime"
    private $collection =>
    bool(false)
    private $collectionKeyType =>
    NULL
    private $collectionValueType =>
    NULL
  }
}
array(1) {
  [0] =>
  class Symfony\Component\PropertyInfo\Type#36 (6) {
    private $builtinType =>
    string(3) "int"
    private $nullable =>
    bool(false)
    private $class =>
    NULL
    private $collection =>
    bool(false)
    private $collectionKeyType =>
    NULL
    private $collectionValueType =>
    NULL
  }
}
array(1) {
  [0] =>
  class Symfony\Component\PropertyInfo\Type#245 (6) {
    private $builtinType =>
    string(6) "object"
    private $nullable =>
    bool(false)
    private $class =>
    string(11) "SplFileInfo"
    private $collection =>
    bool(false)
    private $collectionKeyType =>
    NULL
    private $collectionValueType =>
    NULL
  }
}
bool(true)
bool(false)
bool(true)
bool(true)
string(35) "This is a date (short description)."
string(24) "With a long description."

* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
* (c) Kévin Dunglas <dunglas@gmail.com>
Copy link
Member Author

Choose a reason for hiding this comment

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

Not sure if it is required or not as this code was in the wild previously but I'm ok to remove this line if necessary.

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 no license expert, but I think it would be better to be consistent with everything. We can talk about that on the phone.

@mickaelandrieu
Copy link
Contributor

👍 this is realy useful

* file that was distributed with this source code.
*/

namespace Symfony\Component\PropertyInfo\Extractors;
Copy link
Member

Choose a reason for hiding this comment

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

we generally use singular for namespaces in Symfony

@theofidry
Copy link
Contributor

👍

@dbu
Copy link
Contributor

dbu commented Sep 21, 2015

what about the doctrine variants (mongo, phpcr)? can they provide their own extractor in their symfony bundle?

return array(new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, 'DateTime'));

case 'array':
return array(new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true, new Type(Type::BUILTIN_TYPE_INT)));
Copy link
Member

Choose a reason for hiding this comment

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

this supports string keys too

@dunglas
Copy link
Member Author

dunglas commented Sep 21, 2015

@dbu IMO it could even be added directly in the Doctrine bridge.

composer require symfony/property-info

To use the PHPDoc extractor, install the [phpDocumentator's Reflection](https://github.com/phpDocumentor/Reflection) library.
To use the Doctrine extractor, install the [Doctrine ORM](http://www.doctrine-project.org/projects/orm.html).
Copy link
Member

Choose a reason for hiding this comment

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

You should mention that you also need the Doctrine bridge.

@fabpot
Copy link
Member

fabpot commented Sep 22, 2015

Can you rebase to get rid of all the merge commits that we don't want to keep when merging?

@fabpot
Copy link
Member

fabpot commented Sep 22, 2015

LGTM

@stof
Copy link
Member

stof commented Sep 22, 2015

before the merge here, I would like to see the documentation PR being opened, which will help us see how this component is mean to be used (as we will be able to read the documentation)

@dunglas
Copy link
Member Author

dunglas commented Sep 22, 2015

@stof doc added
@fabpot CS and license fixed. Rebasing is a pain because of all files in common at the root in old versions. If merge commits are really a problem, IMO the best is to get rid of the history. But maybe some Git gurus here know a solution to avoid all those rebasing conflicts.

@dunglas
Copy link
Member Author

dunglas commented Sep 22, 2015

The AppVeyor error is unrelated.

@fabpot
Copy link
Member

fabpot commented Sep 23, 2015

@fabpot I can still see some licenses that should be fixed. Regarding the history, external contributions are minimal, so loosing the history should not be a problem; especially because there are a lot of noise in there (including the Hack patch that was later reverted).

@fabpot
Copy link
Member

fabpot commented Sep 24, 2015

ping @symfony/deciders

@@ -76,7 +77,11 @@
"monolog/monolog": "~1.11",
"ircmaxell/password-compat": "~1.0",
"ocramius/proxy-manager": "~0.4|~1.0",
"egulias/email-validator": "~1.2"
"egulias/email-validator": "~1.2",
"phpdocumentor/reflection": "~1.0"
Copy link
Member

Choose a reason for hiding this comment

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

You've added a conflict block below for versions < 1.0.7. Shouldn't we change the version constraint instead to ^1.0.7 and drop the conflict block?

Copy link
Member Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

Oh, I've just found the other composer.json with the discussion about this topic. I'll join there. Nevermind. ;-)

@derrabus
Copy link
Member

Let's test this Carson thingy…

Status: Reviewed

@derrabus
Copy link
Member

🎉

@OskarStark
Copy link
Contributor

@carsonbot ...

Status: Reviewed

@dunglas
Copy link
Member Author

dunglas commented Sep 24, 2015

Issues raised by @derrabus and @OskarStark fixed.

@fabpot
Copy link
Member

fabpot commented Sep 25, 2015

Reading the documentation, here are some thoughts:

  • The PropertyInfo class name is confusing; it looks like a class that represents a single property;
  • About the constructor arguments of PropertyInfo: Would it be easier for end users to pass one list of extractors (they would all implement an empty marker interface) and then, depending on the interfaces they implements, we can easily separate them into 4 buckets. The only drawbacks I can see is if the ordering would be different depending on the interface they implement but I doubt it's the case.

@dunglas
Copy link
Member Author

dunglas commented Sep 25, 2015

  • Do you have a suggestion for a better name? What do you think about PropertyInfoExtractor?
  • The ordering matters and it's exactly why arguments they are one argument by type. The first implementation was exactly like you describe but when developing API Platform I found the following particular use case: list of properties must be extracted using reflection but type with the Doctrine extractor and it's not possible without segregating the arguments. IMO it's not a big deal from developper POV because the component will be exposed as a service (I'll provide a PR when this one will be merged) in the full stack framework. Developers using the standalone component probably have enough background to understand the ordering issue.

@dunglas
Copy link
Member Author

dunglas commented Sep 25, 2015

Another solution for the number of arguments: the constructor as is but provide a factory method with only one parameter (the array of extractors) doing the segregation.

It looks overkill for such a low level component but I can add it if you think it's better in term of DX.

@fabpot
Copy link
Member

fabpot commented Sep 25, 2015

PropertyInfoExtractor sounds good to me.
As the ordering matters, let's keep the current constructor as is.

@dunglas
Copy link
Member Author

dunglas commented Sep 25, 2015

Class and interfaces renamed accordingly.

@fabpot
Copy link
Member

fabpot commented Sep 25, 2015

👍

@fabpot
Copy link
Member

fabpot commented Sep 26, 2015

Thank you @dunglas.

@fabpot fabpot closed this in 59ee12c Sep 26, 2015
@fabpot
Copy link
Member

fabpot commented Sep 26, 2015

@dunglas dunglas deleted the propertyinfo branch October 29, 2015 12:32
@fabpot fabpot mentioned this pull request Nov 16, 2015
weaverryan added a commit to symfony/symfony-docs that referenced this pull request Aug 20, 2016
This PR was merged into the 2.8 branch.

Discussion
----------

[PropertyInfo] Add Component Documentation

| Q             | A
| ------------- | ---
| Doc fix?      | no
| New docs?     | yes (symfony/symfony#15858)
| Applies to    | `2.8`, `3.0`
| Fixed tickets | N/A

This is still a *work in progress*, but I'd like feedback from anyone regarding structure, grammar and any other improvements while I continue. After speaking with @dunglas, I'm creating a new PR due our branches differing by about 400 commits.

Commits
-------

a0409d7 Update Reference to Service Container Tags
78ea4a5 Update PropertyAccess Component Path
7b786af Fix Incorrect Indent
96b139b Suggested Changes
cf7a0ea Add PropertyInfo Component Documentation
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.