Doctrine Fixtures: getOrder() with Join Tables - symfony

How do you control the order of fixture loading when two fixtures depend on each other to load?
My schema has a Book entity, an Author entity, and a BookAuthor entity. Books can have many authors, and BookAuthor is required because it has an additional field called 'main' indicating whether the author is the main author of the book.
In BookFixtures, I reference BookAuthorFixtures:
$book1->addBookAuthor($manager->merge($this->getReference('book-author-1')));
In BookAuthorFixtures, I reference BookFixtures:
$bookAuthor1->setBook($manager->merge($this->getReference('book-1')));
One of the fixtures must be loaded first, which means the fixture it references is an undefined index.
Is there a trick to solving this issue?
This question addresses almost the same issue, but the configuration is different and the issue went unresolved despite the accepted answer.

I don't know exactly how did you set up your relationships, but I think that this is what you should do:
1) Load the Author fixtures (they should require any books to be created)
2) Load the Book Fixtures. While you are creating the fixtures, in your load() method, you can create the "BookAuthor" entity for each book, and the book entity should be configured to save the BookAuthor entities it holds when it's persisted. The property "book_authors" inside the book entity could be something similar to this:
/**
* #ORM\OneToMany(targetEntity="your\bundle\Entity\BookAuthor",mappedBy="book", cascade={"persist", "remove"})
*/
protected $book_authors;
So in the Book fixtures, the code snippet that creates a book might be (don't forget to set any extra data, it's just a sample):
// [...]
$book = new Book();
$book->setTitle( 'xxx' )
// Set more data...
$book_author = new BookAuthor();
$book_author->setAuthor( $manager->merge($this->getReference('author-1')) );
$book_author->setBook( $book );
$book->addBookAuthor( $book_author );
$em->persist( $book );
// [...]
I hope it helped!

Related

Create new element with doctrine entity manager?

I use doctrine entity manager in my script, select and update works always, so entity manager is initialized correctly:
$article = $entityManager->find('Models\Article', 5);
echo $article->getTitle();
or:
$article->setTitle('Updated!');
but when I try to create/save new element then the page breaks, the code is:
$item = new Article();
$item->setAuthorId(1);
$item->setTitle('Created item!');
$entityManager->persist($item);
$entityManager->flush();
It's created like on official documentation page
What I do wrong here?
Seems you can't specify the relation of the object with the Author entity:
$item->setAuthorId(1);
Probably your entity Article Have a relation with the entity Author. In this case you should have a proper setter method (simple setAuthor(Author $author) ) that assign the reference of an Author object. In this case you could use the following:
$item->setAuthor($entityManager->find('Models\Author', 1););
Or Better
$item->setAuthor($entityManager->getReference('Models\Author', 1););
You could also use a short way of reference the class object with the class keyword, as example:
$item->setAuthor($entityManager->getReference(Author::class, 1););
Hope this help

Set up non-persistent relation in Doctrine 2

I have an object $user that has a one to many relation with $establishment. I can use:
$user->getEstablishments();
The user can select a stablishment to work on. I have this method that I call in the controller:
$user->setCurrentEstablishment($establishment);
And this one that I call in the view:
$establishment = $user->getCurrentEstablishment();
I want to be able to call:
$user->setCurrentEstablishmentBy Slug($establishment_slug);
where the slug is a string, and let the user object look for the establishment.
Doctrine discourages the practice of accessing the Entity Manager inside the Entity object, but I think that using it in the controller is even worse.
I suspect that some special Doctrine annotation exists that takes care of non persistent relations like this, or some method other than serving the Entity Manager through a service should be used here. Some easy way of referencing other entities from inside the model.
¿Is there any? ¿How could I do that?
There is no Annotation in Doctrine which could convert slug into object.
What can help You is ParamConverter, with it you can automatically convert slug from query into object. But it still must be used in Controller.
Example usage:
/**
* #Route("/some-route/{slug}")
* #ParamConverter("object", class="AppBundle:Establishment", options={"id" = "slug", "repository_method" = "findEstablishmentBySlug"})
*/
public function slugAction(Establishment $object)
{
...
Docs about param converter: http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html

Symfony2 - How to Dynamically get a Doctrine entity's Entity Manager

We are building a CMS and website building platform with a lot of different vendors and clients sites, so there are a lot of different content type entities, which are edited by generic controllers and helper services that don't necessarily (easily) know what the entity manager is for a given entity.
NOTE: We have several entityManagers to separate access to different databases, e.g. Global, Billing, Local, etc
There are many cases where we need to detect what is the entity's EntityManager. For example, we have a MediaHelper that dynamically associates media from a database with matching fields on the entity (this doesn't work with associations because the Media has to connect with literally any entity and you can't have that kind of dynamic association and we don't want a hundred different associations).
The media is in a bundle managed by the 'Local' EntityManager. But the entity may be in a 'Global' EntityManager (you can't assume it's in the same entity manager). So we need to detect and persist the right entity manager for the right entity.
So how do you recommend dynamically detecting the entityManager for an entity?
Original Custom Method
NOTE: the accepted answer is a much better solution. This is just here for archival purposes.
Here is a simple solution that works. But I don't know enough about Symfony and Doctrine to know if it's a bad idea? Does anyone else know? If not, I don't know why this wouldn't be in the core, as a Doctrine Utility.
I created an EntityHelper service that injects the Doctrine service into it:
gutensite_cms.entity_helper:
class: Gutensite\CmsBundle\Service\EntityHelper
arguments:
- "#doctrine"
Then in the entity helper is one simple function to get the Entity Manager for an entity (the config.yml registers the bundles for entity managers already):
/**
* Automagically find the entityManager for an entity.
* #param $entity
* #return mixed
*/
public function getManagerForEntity($entity) {
$className = \Doctrine\Common\Util\ClassUtils::getRealClass(get_class($entity));
foreach (array_keys($this->doctrine->getManagers()) as $name) {
if(in_array($className, $this->doctrine->getManager($name)->getConfiguration()->getMetadataDriverImpl()->getAllClassNames())) return $em;
}
}
NOTE: Doctrine Registry#getAliasNamespace already does something nearly identical to this foreach loop, I just modified the idea to return the entity manager instead of the namespace, e.g.
public function getAliasNamespace($alias) {
foreach (array_keys($this->getManagers()) as $name) {
try {
return $this->getManager($name)->getConfiguration()->getEntityNamespace($alias);
} catch (ORMException $e) {
}
}
throw ORMException::unknownEntityNamespace($alias);
}
Update 10/21/15: Entity Detection Code updated per #Cerad's suggestion.
Per the suggestion of #qooplmao, there is an easy method already in the Doctrine core.
// 1) get the real class for the entity with the Doctrine Utility.
$class = \Doctrine\Common\Util\ClassUtils::getRealClass(get_class($entity))
// 2) get the manager for that class.
$entityManager = $this->container->get('doctrine')->getManagerForClass($class);
Updated 10/22/15 After suggestions from Cerad and Qooplmao
Can you not give the entity manager a alias that suits the context it is for? You talk about Global, Billing, Local, so for example:
'service_manager' => array(
'aliases' => array(
'global_entity_manager' => 'My\Global\EntityManager',
'billing_entity_manager' => 'My\Billing\EntityManager',
'local_entity_manager' => 'My\Local\EntityManager',
),
)
You could also map the entity manager to the namespace of the entity.
So let's say you have a folder for your Global entities that is Global\Entity, then you could alias the entity manager for those entities Global\Entity\EntityManager. The advantage of this solution is that you can map several namespaces to the same entity manager, so your Billing and Global entities can easily share the same entity manager:
'service_manager' => array(
'aliases' => array(
'Global\Entity\EntityManager' => 'My\Global\EntityManager',
'Billing\Entity\EntityManager' => 'My\Global\EntityManager', // <-same name
'Local\Entity\EntityManager' => 'My\Local\EntityManager',
),
)
This only works if your entities in one namespace are manager by the same EntityManager instance. I can hardly believe this would not be the case in any project, but otherwise you should maybe reorganize a bit? :D

Doctrine many-to-many association is not resolved

When i am using a Many-To-Many relationship in Symfony2 using Doctrine ORM i get the problem that my many-to-many relationship is not resolved.
Example:
Class A:
/**
* #ORM\ManyToMany(targetEntity="StoreItem", mappedBy="itemOptions")
*/
protected $storeItems;
Class B:
/**
* #ORM\ManyToMany(targetEntity="StoreItemOption", inversedBy="storeItems")
* #ORM\JoinTable(name="store_item_itemoptions")
*/
protected $itemOptions;
now i store the object in a session, note that i did not called the many to many relationship yet by using
->getItemOptions()
When i get my session object now and do ->getItemOptions() then it is empty.
Anybody has an idea what is causing this?
(PS: I found a hacky solution by saying that when i add an item to my cart i do a empty foreach that calls the method ->getItemOptions())
This is called 'lazy loading', and is a doctrine feature designed to reduce memory overhead.
You can set loading to 'eager' or explicitly add a select for the other field in your DQL to avoid lazy loading: e.g.:
$objectsA=$em->createQueryBuilder('\Class\A', 'a')
->join('a.b', 'b')
->addSelect('b')
->getQuery()
->getResult();

Symfony2.1 Circular references

I'm wondering how to avoid having a circular reference in my symfony2.1 application.
I have an entity like
customer (
name
addresses -- OneToMany
currentAddress -- OneToOne )
and
address (
street
customer -- ManyToOne )
Now my fixtures won't load because it can't delete the customer because of the foreign key.
For performances' sake I would like to avoid having to add a getCurrentAddress() method on customer which would select in the addresses table.
Does anybody have a solution for that?
Adding a getCurrentAddress() isn't such a performance issue.
This way, I'll avoid the circular reference and all the issues that come along with it.
In my situation, using an order by date in the doctrine annotation was enough:
// on customer entity :
/** #ORM\OrderBy({"datemodified" = "DESC"}) */
private $addresses
public function getCurrentAddress()
{
return $this->addresses[0];
}

Resources