[Doctrine2]Flush fail but unitOfWork process correctly - symfony

I hope this question haven't already answered but i don't find it.
I using doctrine2 in my symfony (3.4) project. I use persist and flush so many times into it without any problems throught container, in a little piece of code i have some trouble i can't figure out...
In my controller i have a code like this :
$obj = $this->container->get('some.service')->initiateObj(some_params);
$this->getManager()->persist($obj);
$this->getManager()->flush();
// I can't dump here
My object is set and returned correctly from my first code line.
The persist function work perfectly. If i dump my object after persist, doctrine event setting for this object right sets.
After the flush i have an error 500 from my browser (chromium).
I was thinking the problem were in a pre/postFlush event, but when a dump in doctrine EntityManager code, the unitOfWork->commit function work correctly without error and i can dump after it.
But i can't dump in my controller just after flush...
Here the EntityManager from doctrine code :
public function flush($entity = null)
{
$this->errorIfClosed();
$this->unitOfWork->commit($entity);
// I can dump here
}
I haven't any symfony/doctrine log from that, no apache2 log too.
Is anyone have an idea from where an error can throw after the commit function ?
Thank you very much for your help !

I have found my solution last week, in my code.
It was in postPersist event. But i don't really understand why symfony, doctrine... raise any exception, just a blank screen with an error 500.
Thanks you for your help.

Related

Doctrine2 - A new entity was found through the relationship [...]

Wow, this is very strange:
$bar = new Bar();
$foo = $entity->getFoo();
$bar->setFoo($foo);
$em->persist($bar);
$em->flush();
and I obtain the following message
A new entity was found through the relationship [....]
By reading on the net, I undertand that if fetch two object from two different entity managers, one manager will doesn't know about entities fetched from other manager. Since here I'm into a "db hook" (postPersist) and I've manager injected from DIC, I've tried to change my code in agreement:
$bar = new Bar();
$foo_id = $entity->getFoo()->getId();
$foo = $em->getRepository('MyBundleName:Foo')->findOneBy(array('id'=>$foo_id));
$bar->setFoo($foo);
$em->persist($bar);
$em->flush();
but nothing changed.
Can someone point me to right direction and, most important, explain what's going on here?
UPDATE
I've migrated all code outside db hooks and I've created a new service that will do pretty much same things of hooks but has to called explicitly after flush() Is very strange, however, that nothing changed. I've also tried to use spl_obj_hash onto entity manager for retrieve information about the entity manager who flush object into db and "other one" that will retrieve $foo from db and try to persist $bar.
This is the result:
SPL_OBJ ENTITY MANAGER - 1: 0000000021770e03000000001eda54f7
SPL_OBJ ENTITY MANAGER - 2: 0000000021770e03000000001eda54f7
if I'm not wrong, they're the same entity manager object. I'm pretty confused actually...
UPDATE - WORKING CODE
I've found a "code combination" that will do the work but I'm still pretty confused about it.
If I use first snippet of code (where $foo is retrieved from $entity itself) and flush only $bar, error is still there.
If I use second snippet of code (where $foo is retrieved from entity manager) and persist only $bar, all works properly (obviosuly if I call $flush() without parameters, issue is still there)
I had the same problem and resolved it, I'm posting it because I haven't seen it mentioned anywhere and it might help someone.
I have a service that parses data & persists it to entities, service to which I'm feeding the entityManager & child entities. And I started to have the same error on persist. Using merge() didn't help as it just threw me "A managed dirty+entity [...]" error instead.
After a little digging it seems that as far as Doctrine is concerned the entities I was feeding my service came from a different entityManager, so you actually have to get the entities from the entityManager inside the service if you are using it to persist.
I fixed mine by removing clear
$this->getDoctrine()->getManager()->clear();
I'm not sure since I never had this issue before and right now I'm not in the position to replicate it. But I will give you some options I would try:
If the two entitymanagers are using the same database you can merge (http://docs.doctrine-project.org/en/2.0.x/reference/working-with-objects.html#merging-entities) the entity into the other entitymanager. In this case that will look something like this:
$em->merge($foo);
This makes sure the entity $foo is managed by your entitymanager.
Also, remember that a postPersist is executed after the database operations. I think you have better chances if you try your modified code in a prepersist method.
As the documentation says:
prePersist - The prePersist event occurs for a given entity before the respective
EntityManager persist operation for that entity is executed.
postPersist - The postPersist event occurs for an entity after the entity has
been made persistent. It will be invoked after the database insert
operations. Generated primary key values are available in the
postPersist event.
Full documentation can be found here: http://docs.doctrine-project.org/en/2.0.x/reference/events.html#lifecycle-events
Just try this and let me know the result
Try : $em->merge($bar);
$bar = new Bar();
$foo = $entity->getFoo();
$bar->setFoo($foo);
$em->merge($bar);
$em->flush();
[1] Doctrine - A new entity was found through the relationship
It's not so clear from your code, but I think you create a new $foo, but you don't save it before to save $bar.
Try this:
$em->persist($foo);
$em->flush();
$bar->setFoo($foo);
$em->persist($bar);
$em->flush();
In general you can escape this by using cascade=persist on the association of your entities.

How to access the Doctrine replace() method?

I am doing my first project with Symfony2 + Doctrine, and currently trying to implement replacing records. However when I try to call
$em->save($product);
or
$em->replace($product);
(instead of)
$em->persist($product);
I get fatal errors. So I started digging around to try to find the persist() method so I could see what other methods were available. I searched the entire contents of the vendors/doctrine directory and could not find any references to the persist or flush methods. Where the heck are these located? I tried following the code but quickly got lost.
So the main question: How can I do a replace() with doctrine in Symfony2?
Sub-question: Where are the persist() and flush() methods? Not being able to find them is frustrating in itself.
Incase somebody else is wondering, try looking into:
$em = $service->get('doctrine.orm.entity_manager');
$entity = $em->merge($entity);
$em->flush();
From the docs, Doctrine\ORM\EntityManager::merge():
Merges the state of a detached entity into the persistence context of
this EntityManager and returns the managed copy of the entity. The
entity passed to merge will not become associated/managed with this
EntityManager.
Should do the trick for you.
I don't think that Doctrine's replace() method is supported in Symfony, or at least it is not accessible through EntityManager.
If you need to update your existing entity, then you can simply do it as described here - http://symfony.com/doc/current/book/doctrine.html#updating-an-object.
As for persist() and flush() methods - you can find them in vendor/doctrine/common/lib/Doctrine/Common/Persistence/ObjectManager.php

symfony2 / doctrine2 flush createas a select after delete

I'm removing an entity with these commands:
$this->getEntityManager()->remove($exclusivedeal->getPicture());
$exclusivedeal->setPicture();
$this->getEntityManager()->flush();
$this->getEntityManager()->getConnection()->commit();
The picture Attribute is a ManyToOne relation to the picture entity.
The picture Entity has a function that is called via the postremove Annotation to remove the picture physically from the filesystem. The Flush() operation is doing the sql statements. After the delete Statement, an select statement is called too. This creates the following error:
[2012-06-07 10:06:46] request.CRITICAL: Doctrine\ORM\EntityNotFoundException: Entity was not found. (uncaught exception) at C:\xampp\htdocs\forum\app\cache\dev\doctrine\orm\Proxies\__CG__DankeForumBundleEntityPicture.php line 32 [] []
When i change the annotation to preRemove, everything is fine, but this can't be the solution. I'm doing the same operation on an other Entity with a relation to the Picture Entity.
When i set the cascade remove annotation, the same problem is happened.
Has anyone an idea what i'm doing wrong?
Thank you very much.
I had the same issue and it gave me a lot of headaches trying to solve the problem. I finally found the issue.
The cookbook on the symfony website for handling file uploads with doctrine has been updated to solve this issue.
I just hit this exact same problem and found the issue in my case was because I was using both cascade={"all"} (i.e 'remove') and onDelete="CASCADE".
Changing the cascade to "persist" solved it and Im now able to delete entities with image associations.

How do I get an ID after saving an ExtBase Model?

After creating a model and adding it to a repository I want to have the new ID for different purposes (creating a mail, updating other fields outside the Extbase world)
$page = t3lib_div::makeInstance('Tx_MyExt_Domain_Model_Page');
$page->setTitle('Hello World');
$this->pageRepository->add($page);
At this point $page hasn't got an ID yet, uid is null.
$page->getUid(); // returns null
When does it get it? And how can I retrieve in on runtime?
In ExtBase, objects are "managed". This means every persistence transaction (add/remove/update) is simply noted in the underlying logic, but not yet executed until the appropriate time (like the end of processing a request). So, just because you add an object to a repository doesn't mean that it's actually added yet. That actually happens once $persistenceManager->persistAll() is called, which isn't something you need to do manually, ever. The point is, your $page object won't have a UID until it's saved and that's why $page->getUid() returns null. Look here for a great explanation.
I suspect that you are trying to do something outside of the ExtBase object/MVC lifecycle. At least, last time I got null when I tried to get the UID of an object, it was because I wasn't operating within the framework appropriately.
However, if you post some more code and give us a bigger picture of what you're trying to achieve, maybe we can help you get to a point where that object actually has a UID. For instance, if you're in a Controller object, tell us which Action method you're in, or if you're in a Repository object, tell us what you're trying to get from the repository and where/how you plan on using the query results.
EDIT
Just guessing here, but I'm assuming you're executing this code in some action of a controller. Since after the controller is executed a view is rendered, you can just pass the page object to the view:
$this->view->assign('page', $page);
And then in your view you can use the page object in a link:
<f:link.action action="show" arguments="{page:page}">
See this page object
</f:link.action>
And then in the show action of your controller you can show the page:
public function showAction(Tx_MyExt_Domain_Model_Page $page) {
// Do whatever you need to show the page in the `Show.html` template
}
I really am just guessing here. If you can give us a larger picture of what you're trying to do, what your action methods are supposed to do and things like that, we can answer your question a little more confidently.
(I'm also assuming that your page object isn't a replacement for the regular TYPO3 pages and that they are something totally different. It's much easier to deal with those TYPO3 pages through the backend interface than at the php level.)
You can call persistence manager explicitly in Your controller like this
#TYPO3 4.x
$persistenceManager = $this->objectManager->create('Tx_Extbase_Persistence_Manager');
$persistenceManager->persistAll();
#TYPO3 6.x
$persistenceManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager');
$persistenceManager->persistAll();

Problem persisting collection of interfaces in JDO/Datanucleus. "unable to assign an object of type.."

I am getting below error whilst trying to persist an object that has a collection of interfaces which I want to hold a couple of different types of objects. Seems to be happening almost randomly. Sometimes after restarting it works ok ( I might be doing something wrong though).
class CommentList {
#Persistent
#Join
ArrayList<IComment> = new ArrayList<IComment>();
}
somewhere else...
CommentList cl = new CommentList();
cl.addComment( new SimpleComment() );
cl.addComment( new SpecialComment() );
repo.persist( cl );
I can see the join table has been created in my DB along with ID fields for each of the Implementation classes of IComment.
SimpleComment and SpecialComment implement IComment. If I just add a SimpleComment it works fine. As soon as I start trying to add other types of objects I start to get the errors.
error im getting
java.lang.ClassCastException: Field "com.myapp.model.CommentList.comments" is a reference field (interface/Object) of type com.myapp.behaviours.IComment but DataNucleus is unable to assign an object of type "com.myapp.model.ShortComment" to this field. You can only assign this field to a type specified by the "implementation-classes" extension attribute.
at org.datanucleus.store.mapped.mapping.MultiMapping.setObject(MultiMapping.java:220)
at org.datanucleus.store.mapped.mapping.ReferenceMapping.setObject(ReferenceMapping.java:526)
at org.datanucleus.store.mapped.mapping.MultiMapping.setObject(MultiMapping.java:200)
at org.datanucleus.store.rdbms.scostore.BackingStoreHelper.populateElementInStatement(BackingStoreHelpe
r.java:135)
at org.datanucleus.store.rdbms.scostore.RDBMSJoinListStoreSpecialization.internalAdd(RDBMSJoinListStore
Specialization.java:443)
at org.datanucleus.store.mapped.scostore.JoinListStore.internalAdd(JoinListStore.java:233)
When it does save, if I restart the server and try to query for a list of the comments, I get null values returned.
I'm using mysql backend - if I switch to db4o it works fine.
Please let me know if any info would be useful.
If you have any idea where I might be going wrong or can provide some sample code for persisting collection of different objects implementing the same interface that would be appreciated.
Thanks for any help.
Tom
When I used interfaces I just enabled dynamicSchemaUpdates (some persistence property with a name like that) and FK's are added when needed. The log gives all SQL I think
I fixed this by specifying
<extension implemention-classes="SimpleComment SpecialComment"/>
for the field cl in my pacakge.jdo.

Resources