Removing the metadata instantiation from the EM#7143
Removing the metadata instantiation from the EM#7143mikeSimonson wants to merge 23 commits intodoctrine:old-prototype-3.xfrom
Conversation
The metadata instantiation is kept in the create method for BC for now. A new static method is added to be able to pass the metadata to the EM.
|
@Ocramius Is this what you meant when we discussed at phpbenelux ? |
|
@mikeSimonson the idea was to make the metadata a |
|
I just wanted to make sure that I was going in the right direction. |
|
@mikeSimonson I'd suggest making it an eager map for now, and later we fix it with |
|
Does the new commit goes in the right direction ? Can I How do I proceed to remove the entity manager from the OnClassMetadataNotFoundEventArgs in the ClassMetadataFactory and LoadClassMetadataEventArgs ? Any other remarks / comment / direction ? |
lib/Doctrine/ORM/EntityManager.php
Outdated
| /** | ||
| * @return MetadataCollection | ||
| */ | ||
| public function getMetadatas(): MetadataCollection |
There was a problem hiding this comment.
Would avoid exposing it here at all.
lib/Doctrine/ORM/EntityManager.php
Outdated
| * @return MetadataCollection | ||
| */ | ||
| public function getConnection() | ||
| public function getMetadatas(): MetadataCollection |
lib/Doctrine/ORM/EntityManager.php
Outdated
| public function getClassMetadata($className) : Mapping\ClassMetadata | ||
| { | ||
| return $this->metadataFactory->getMetadataFor($className); | ||
| $className = StaticClassNameConverter::getRealClass($className); |
There was a problem hiding this comment.
This can likely be dealt with in a MetadataCollection decorator instead
lib/Doctrine/ORM/EntityManager.php
Outdated
| $this->conn = $conn; | ||
| $this->config = $config; | ||
| $this->eventManager = $eventManager; | ||
| $this->metadatas = $metadataCollection; |
There was a problem hiding this comment.
metadata is irregular: the plural of metadata is metadata. A better way to name this is probably mappings
| try{ | ||
| $this->metadatas->get(StaticClassNameConverter::getClass($value)); | ||
| $id[$i] = $this->unitOfWork->getSingleIdentifierValue($value); | ||
| } catch (\Exception $e) { |
| try{ | ||
| $this->metadatas->get(StaticClassNameConverter::getClass($value)); | ||
| $id[$i] = $this->unitOfWork->getSingleIdentifierValue($value); | ||
| } catch (\Exception $e) { |
There was a problem hiding this comment.
Likely wrong here - why did you introduce these try-catches? I know you are still playing around with the patch: just wondering why this got added to make things work
There was a problem hiding this comment.
just because for now get throws an Exception if the metadata is not found where it wasn't before.
| return new EntityManager($connection, $config, $connection->getEventManager()); | ||
| $metadataFactoryClassName = $config->getClassMetadataFactoryName(); | ||
| /** @var \Doctrine\Common\Persistence\Mapping\ClassMetadataFactory $metadataFactory */ | ||
| $metadataFactory = new $metadataFactoryClassName($config, $connection, $eventManager); |
There was a problem hiding this comment.
👍 this is a decent BC-compliant approach for now :)
| return $this->classMetadatas[$name]; | ||
| } | ||
|
|
||
| public static function fromClassMetadatas(array $classMetadatas) |
There was a problem hiding this comment.
I suggest using (ClassMetadata $firstClass, ClassMetadata ...$otherClasses) here, which prevents instantiation if no metadata is available at all.
|
|
||
| public function get($name) | ||
| { | ||
| if(!isset($this->classMetadatas[$name])){ |
There was a problem hiding this comment.
Add the class name normalisation here
|
|
||
| private function __construct(array $classMetadatas) | ||
| { | ||
| $metadataByClassName = array_reduce ( |
There was a problem hiding this comment.
This is simpler with:
array_combine(
array_map(function (ClassMetadata $metadata) { return $metadata->getClassName(); }, $metadata),
$metadata
);
👍
Most likely. Metadata caching can be moved to a
That is a subtle BC break: please don't change that. Yes: since metadata now has a lifecycle that is completely separate from the ORM itself, removal is fine here 👍
I suggest we completely remove these events, as the user can simply decorate the
Provided above :-) |
as it's completely separeted from the ORM lifecycle now, at least it's the goal
Making sure that it can't be instantiated with an empty array
| return $this->metadata[$name]; | ||
| } | ||
|
|
||
| public static function fromClassMetadatas(ClassMetadata $firstClass, ClassMetadata ...$otherClasses) |
There was a problem hiding this comment.
Why is this a static instead of constructor directly?
Also the signature is ugly, let's just have __construct(ClassMetadata ...$metadata) with assert(count($metadata) !== 0) if it really MUST be non-empty.
|
|
||
| default: | ||
| $class = $this->config->getCustomHydrationMode($hydrationMode); | ||
| $class = $this->config->getCustomHydrationMode((string) $hydrationMode); |
There was a problem hiding this comment.
This is most likely wrong, see #7130 (comment). It could be int|string currently.
There was a problem hiding this comment.
getCustomHydrationMode expect a string in it's function definition.
There was a problem hiding this comment.
Changed this in my PR since it's really int|string now. Something to re-do later on probably.
|
@Ocramius My main question now is to know if passing the whole mapping collection to the BasicEntityPersister is the way to go ? (commit extract the MetadataFactory from the basic entity persister and the following one) |
Ocramius
left a comment
There was a problem hiding this comment.
@Ocramius My main question now is to know if passing the whole mapping collection to the BasicEntityPersister is the way to go ? (commit extract the MetadataFactory from the basic entity persister and the following one)
@mikeSimonson I'd suggest that any component requiring metadata should just be given the collection. The MetadataCollection is now to be considered a "dumb" immutable structure, so it should be fine to pass it around.
Obviously, if only one entity metadata is required in a persister, then it should be passed in explicitly, but I don't know how big that change would be.
It will be easy to extract these scenarios when looking at classes that always get() on the collection with the same parameter.
| try{ | ||
| $this->mappings->get($value); | ||
| $id[$i] = $this->unitOfWork->getSingleIdentifierValue($value); | ||
| } catch (\Exception $e) { |
There was a problem hiding this comment.
We need to get rid of these later on.
| foreach ($id as $i => $value) { | ||
| if (is_object($value) && $this->metadataFactory->hasMetadataFor(StaticClassNameConverter::getClass($value))) { | ||
| $id[$i] = $this->unitOfWork->getSingleIdentifierValue($value); | ||
| if (is_object($value)) { |
There was a problem hiding this comment.
The API for getting metadata by object or string should be separate
| if (is_object($value) && $this->metadataFactory->hasMetadataFor(StaticClassNameConverter::getClass($value))) { | ||
| $scalarId[$i] = $this->unitOfWork->getSingleIdentifierValue($value); | ||
| if (is_object($value)) { | ||
| try{ |
There was a problem hiding this comment.
Same here - try-catch block needs to go
| if (is_object($value) && $this->metadataFactory->hasMetadataFor(StaticClassNameConverter::getClass($value))) { | ||
| $id[$i] = $this->unitOfWork->getSingleIdentifierValue($value); | ||
| if (is_object($value)) { | ||
| try{ |
There was a problem hiding this comment.
Same: try-catch should be removed overall. We possibly need a better abstraction.
|
|
||
| public function get(string $name) : ClassMetadata | ||
| { | ||
| $name = StaticClassNameConverter::getRealClass($name); |
There was a problem hiding this comment.
Consider checking for existence before calling StaticClassNameConverter. Copying a metadata reference into a different key is also a good idea for performance reasons
| */ | ||
| private $metadata; | ||
|
|
||
| private function __construct(array $metadata) |
| $this->metadata = $metadataByClassName; | ||
| } | ||
|
|
||
| public function get(string $name) : ClassMetadata |
There was a problem hiding this comment.
The various APIs getting class metadata by object reference could need a getByObject(object $object)
|
|
||
| $config->setMetadataDriverImpl( | ||
| $mappingDriver ?? $config->newDefaultAnnotationDriver([ | ||
| realpath(__DIR__ . '/Models/CMS'), |
There was a problem hiding this comment.
Wondering why this test changed to load everything - is this because we don't yet have a lazy collection?
There was a problem hiding this comment.
Just because I am pocking around a bit everywhere to try and fix everything that I broke.
|
@mikeSimonson I've updated the PR description with the TODOs matching the discussion above. |
|
@mikeSimonson Do you plan to continue with this? |
|
@Majkl578 yes. I don't have much time right now but I hope that I will have it in a good state for amsterdamphp |
|
I'm closing this PR because it hasn't seen progress for several years. Please open a new one if you want to pick up the work one day. |
The metadata instantiation is kept in the create method for BC for now.
A new static method is added to be able to pass the metadata to the EM.
TODOs
\\ltrim()is gone