I have this repetitive piece of code that will be used in more than one entity in my Symfony2 project so will be fine to apply some kind of DRY, if it's possible of course, and I'm thinking in PHP Traits.
private static $preDeletedEntities;// static array that will contain entities due to deletion.
private static $deletedEntities;// static array that will contain entities that were deleted (well, at least the SQL was thrown).
/**
* This callback will be called on the preRemove event
* @ORM\PreRemove
*/
public function entityDueToDeletion()
{
// This entity is due to be deleted though not deleted yet.
self::$preDeletedEntities[] = $this->getId();
}
/**
* This callback will be called in the postRemove event
* @ORM\PostRemove
*/
public function entityDeleted()
{
// The SQL to delete the entity has been issued. Could fail and trigger the rollback in which case the id doesn't get stored in the array.
self::$deletedEntities[] = $this->getId();
}
public static function getDeletedEntities()
{
return array_slice(self::$preDeletedEntities, 0, count(self::$deletedEntities));
}
public static function getNotDeletedEntities()
{
return array_slice(self::$preDeletedEntities, count(self::$deletedEntities)+1, count(self::$preDeletedEntities));
}
public static function getFailedToDeleteEntity()
{
if(count(self::$preDeletedEntities) == count(self::$deletedEntities)) {
return NULL; // Everything went ok
}
return self::$preDeletedEntities[count(self::$deletedEntities)]; // We return the id of the entity that failed.
}
public static function prepareArrays()
{
self::$preDeletedEntities = array();
self::$deletedEntities = array();
}
This is the code I have in mind:
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\HasLifecycleCallbacks()
*/
trait DeleteLifeCycleCallbacksTrait
{
// write things here
}
But will be the Annotation applied to the entity? Is that fine? What would you do it to avoid not repeat the code?
EDIT: Trying to find best approach
Having some ideas from @Cerad user and because as docs says Lifecycle event listeners are much more powerful than the simple lifecycle callbacks then I'll start playing with them.
So, first, the purpose of this Lifecycle Callbacks|Listener|Suscribers
will be store the ID of each persisted object so I can get it in somehow and send back to the view from the controller. As a simple visual example, lets said I send from the view to the controller this array of values (1, 2, 3, 4, 5)
and for some X reason just 1 ,4 and 5 was persisted (mean was complete delete from DB) to DB, right?
Lets said also that I'll use the event listener in Producto
entity. So, whithout test and just getting code from examples, the code should be something like this for the Listener
:
use Doctrine\ORM\Event\LifecycleEventArgs;
use Entity\Producto;
class StoreDeletedIds
{
private $deletedItems = [];
public function postDelete(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
$entityManager = $args->getEntityManager();
if ($entity instanceof Producto) {
array_push($deletedItems, $entity->getId());
}
}
}
My questions|doubts around this are:
- Is the code above fine or doesn't?
- Is
$deletedItems
cleaned every time the listener is invoked by Doctrine? - How do I return
$deletedItems
in order to catch it on the controller and send back to the view? - Do I need to define a Suscriber too? Why?
This are topics new to me so I need some kind of advise
Don't
Business logic doesn't belog into entities.
Traits won't help you either, because while duplicating code is a bad thing, abusing traits is imo even worse.
I once wondered wether I should use traits and posted a question on codereview (https://codereview.stackexchange.com/a/74195/56686). I have yet to stumble upon a valid use case for traits in my applications.
Make a service
I advice you to make a service and put your logic there. Documentation: http://symfony.com/doc/current/book/service_container.html
Because you can't call symfony services from doctrine lifecyclecallbacks, you would have to drop those.
You might wan't to fire up your searchengine of choice to look for a step-by-step tutorial.
Following @PeterPopelyshko comment this is the solution I come with, just define a abstract class
Model\DeleteLifeCycleCallbacks.php
and put the code inside:Then use it as follow: