Symfony: how to cascade undelete when using SoftDeleteable behavior extension? - symfony

My entity User is related to other entities through OneToOne relations, and I'm cascading "delete" for all of them.
I'm using SoftDeleteable behavior extension, so when I remove a User, the entity is not actually removed from the database: the deletedAt field is simply set to DateTime(now), and so are all the deletedAt fields of the related entites.
Now, when I want to restore a User, I do as suggested in the docs:
$em->getFilters()->disable('soft-deleteable');
$user->setDeletedAt(null);
My problem is all the related entities stay deleted when I do this. Any idea how I could cascade the setDeleted(null) to all of them automatically?

Never used this extension but looking at open issues on GH repository I can see quite a few of them related to similar problems when working with associations:
https://github.com/Atlantic18/DoctrineExtensions/issues/656
https://github.com/Atlantic18/DoctrineExtensions/issues/1101
https://github.com/Atlantic18/DoctrineExtensions/issues/505
I'd try first to disable explicitly the filter for each related entity:
$filter = $em->getFilters()->enable('soft-deleteable');
$filter->disableForEntity('Entity\Article');
$filter->disableForEntity('Entity\SomeOtherEntity');
Otherwise I'd add a Listener (and bind it to one of the Doctrine events) to cascade the restore outside of soft-deleteable.

Related

Avoid doctrine postloadEvent if unnecessary

For an blog entry entity I am loading data from an api via the doctrine postloadEvent. For this i created a listener service with an postloadMethod in it.
public function postLoad(BlogEntry $blogEntry)
{
$blogentry->setName($apiClient->getName($blogEntry->getId()))
$blogentry->setContent($apiClient->getContent($blogEntry->getId()))
...
}
This means, there is already a local repository with blog entries. These blogentries are connected to a blog. If i now only want to count the blogentries for each blog, i would implement a getBlogEntryCount() method on the BlogEntry entity and call it.
$blog->getBlogEntryCount();
The problem now is, that the postLoad event is triggered unnecessary, even if i need no data from the api.
How can i avoid this behaviour in doctrine/symfony/sonata admin? Is there mechanism like "lazy loading" for doctrine entities?
Update to Jose M. González Solution
To get only the count of the collection, the extra_lazy loading solution will do it.
For getting local information without triggering the api call i used the said repository function. To get this information working in list view in sonata admin, i created a non-doctrine-related array field "blogEntriesSimple" in my Blog Entity next to my "blogEntries" (which is normally holding the complete entity) field.
I attached an entitylistener with postLoad function to the Blog Entity, which is filling up my blogEntriesSimple array with the information from my custom repository function.
Thats it.
I think this solution is a bit hacky, but until no cleaner solution is available, this will do it.
i think that you can achieve this with the extra lazy associations that permit that you count your related entities without hydrating it
Edited
Also you can do a DQL query that only hidrate a partial view of your entity and it can be used to count the rows and access to your properties, for example:
select be.id,be.title from AppBundle\Entity\BlogEntry be
This query must not trigger the postLoad event
I hope this can help you

How to use attributeOverride properly to disable 'unique' requirement for username and/or password in FOSUserBundle (yaml doctrine configuration)

I'm using FOSUserBundle in a Symfony2 project, and I want to disable the 'unique' attributes on both username and email fields of the User entity. Maybe that sounds strange at first, but I'm using another combination of fields to make sure that there are unique (active) users in my database, which works fine.
Right now I've setup my User.orm.yml as follows:
MyProjectBundle\Entity\User:
type: entity
attributeOverride:
usernameCanonical:
unique: false
emailCanonical:
unique: false
table: fos_user
id:
id:
type: guid
generator:
strategy: UUID
fields:
etc... etc...
When I use this setup, and create/update my database via the console, the UNIQUE indexes are removed from the database, just as I wanted. YAY!
However, when I try to generate my project entities with
doctrine:generate:entities MyProjectBundle
I get the following error:
Invalid field override named 'usernameCanonical' for class 'MyProjectBundle\Entity\User'.
So it is not generating my entities correctly....
For now, I temporarily remove the attributeOverride part in my User.orm.yml whenever I want generate the entities, and put them back again if I wish to update my database.
My project is working fine with this workaround, but I would feel much more comfortable knowing why my attributeOverride is invalid, and set it up correctly...
Anyone with expierience or suggestions?
This was a known bug in the entity generator #3433. It was fixed by #1098 and backported to 2.4 by #1231. You should update to doctrine/orm >=2.4.8.
(By the way the entity generator is for generating entities for the first time and you are supposed to manually edit generated entities after that.)

Doctrine 2 base entities like those in doctrine 1?

I'm starting a new project with Symfony2/Doctrine2 and I generated my entities from the DB with the mapping:convert and mapping:import commands.
My entities are fine, but I only have the generated entities. Back in Doctrine1/Symfony1, you had your entities generated twice : once in the doctrine folder, an almost empty class just extending the second one in doctrine/base folder where all the doctrine internals were (getters/setters, fields...)
This way, you could add your own methods in the first file where they remained untouched even if you generated again the entities (only the doctrine/base files were modified by the generator).
Am I missing something ?
Well the generate command only generates getters and setters that are undefined and appends them to the (entity) file. This means that your custom getters/setters will never be overwritten. Does that answer your question?

Doctrine and Symfony: magic methods and caching

I'm currently implementing the doctrine result cache so I've set
result_cache_driver: apc
into my configuration.
Then I've correctly got query cache working inside the Repository, using for example
->setResultCacheId(sprintf('posts_for_user_%d', $userId))
First problem come when I used these things in doctrine:
$repository->findOneBy(array)
$repository->findBy(array)
which can maybe easily overridden in the repository.
The problem which I can't get past is to use the ParamConverter to use doctrine caching and also entities association.
For example, if I have a Team entity with a OneToMany relation to Player I usually do
$team->getPlayers()
I don't have the control over the caching of that query. Is that possible in some way?
When you run methods like find/findBy or process over PersistentCollection doing $team->getPlayers(), there is UoW which loads the data using EntityPersister and ObjectHydrator to hydrate an object. These objects have no support of result cache driver.
In the other hand, when you use DQL or QueryBuilder, your code products Query object that extends AbstractQuery. If you look inside AbstractQuery::execute you will see this pretty piece of code which makes using of result cache driver possible
$cache = $queryCacheProfile->getResultCacheDriver();
$result = $cache->fetch($cacheKey);
if (isset($result[$realCacheKey])) {
return $result[$realCacheKey];
}
So my suggestion - try load your entities using QueryBuilder and leftJoins on children Collections.
$this->createQueryBuilder('x')->select('x, p')->leftJoin('x.players', 'p')->....;
It'll create the possibility of using result cache driver.

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.

Resources