This course is still being released! Check back later for more chapters.
Fetch the Object ID with Doctrine
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeCurrently, our French translation data is being successfully displayed on the page. However, our current method of fetching the ID using $object->getId() is a bit shaky. It assumes that the user always has a getId() method on their entities, which isn't always the case. We can do better... and Doctrine has our back!
Fetching the Object Manager
Over in our ObjectTranslator::translationsFor() method, above fetching the translations, make some space. First, grab the object manager from Doctrine: $om = $this->doctrine->getManagerForClass(). This needs a class name, so use the passed object's class: $object::class:
| // ... lines 1 - 9 | |
| final class ObjectTranslator | |
| { | |
| // ... lines 12 - 37 | |
| private function translationsFor(object $object, string $locale): array | |
| { | |
| // ... lines 40 - 46 | |
| $om = $this->doctrine->getManagerForClass($object::class); | |
| // ... lines 48 - 76 | |
| } | |
| } |
When using the ORM, you've used something called the entity manager. This is what we're getting here - object manager is a more general interface for it. Again, using these abstract interfaces makes our bundle more flexible.
getManagerForClass() might return null so check for that: if (!$om) { throw new \LogicException(sprintf('No object manager found for class "%s".', $object::class)); }:
| // ... lines 1 - 9 | |
| final class ObjectTranslator | |
| { | |
| // ... lines 12 - 37 | |
| private function translationsFor(object $object, string $locale): array | |
| { | |
| // ... lines 40 - 48 | |
| if (!$om) { | |
| throw new \LogicException(sprintf('No object manager found for class "%s".', $object::class)); | |
| } | |
| // ... lines 52 - 76 | |
| } | |
| } |
Fetching the ID from the Object Manager
Next, $id = $om->getClassMetadata($object::class). This returns a special object that knows all about the Doctrine mapping for this class. ->getIdentifierValues() is what we want. Pass the $object instance:
| // ... lines 1 - 9 | |
| final class ObjectTranslator | |
| { | |
| // ... lines 12 - 37 | |
| private function translationsFor(object $object, string $locale): array | |
| { | |
| // ... lines 40 - 52 | |
| $id = $om->getClassMetadata($object::class) | |
| ->getIdentifierValues($object) | |
| ; | |
| // ... lines 56 - 76 | |
| } | |
| } |
This retrieves the ID for the passed object, regardless of how it's implemented.
dd($id) to see what we are dealing with here. In the browser, refresh. Hmm... It's an array of values... Doctrine supports composite IDs, which basically means multiple ID fields for an entity. This is a pretty advanced feature, and our bundle, at least initially, won't support this.
Even if your entity only has a single ID field, Doctrine still returns it as an array. Remove the dd() and add a check: if (count($id) > 1). Inside, throw new \LogicException(sprintf('Class "%s" must have a single identifier to be translatable', $object::class)):
| // ... lines 1 - 9 | |
| final class ObjectTranslator | |
| { | |
| // ... lines 12 - 37 | |
| private function translationsFor(object $object, string $locale): array | |
| { | |
| // ... lines 40 - 56 | |
| if (1 !== count($id)) { | |
| throw new \LogicException(sprintf('Class "%s" must have a single identifier to be translatable.', $object::class)); | |
| } | |
| // ... lines 60 - 76 | |
| } | |
| } |
Grab the first element of the array with $id = reset($id):
| // ... lines 1 - 9 | |
| final class ObjectTranslator | |
| { | |
| // ... lines 12 - 37 | |
| private function translationsFor(object $object, string $locale): array | |
| { | |
| // ... lines 40 - 60 | |
| $id = reset($id); | |
| // ... lines 62 - 76 | |
| } | |
| } |
dd() that... and refresh the browser. Perfect, just a single value!
Remove the dd() and down in our findBy() array, replace $object->getId() with $id:
| // ... lines 1 - 9 | |
| final class ObjectTranslator | |
| { | |
| // ... lines 12 - 37 | |
| private function translationsFor(object $object, string $locale): array | |
| { | |
| // ... lines 40 - 63 | |
| $translations = $this->doctrine->getRepository($this->translationClass)->findBy([ | |
| // ... lines 65 - 66 | |
| 'objectId' => $id, | |
| ]); | |
| // ... lines 69 - 76 | |
| } | |
| } |
Test it out in the browser... and it worked!
Our ObjectTranslator is working, and pretty solid. Next, let's create a Twig filter for it!