N
N
nuclear2012-04-30 10:40:44
symfony
nuclear, 2012-04-30 10:40:44

Insert in postPersist event?

I need to add an entity after adding other entities. Code (similar for postUpdate):

public function postPersist(LifecycleEventArgs $args) {<br>
    $entity = $args->getEntity(); $em = $args->getEntityManager();<br><br>
    if($entity instanceof FeedItemInterface) {<br>
        $feed = new FeedEntity();<br>
        $feed->setTitle($entity->getFeedTitle());<br>
        $feed->setEntity($entity->getFeedEntityId());<br>
        $feed->setType($entity->getFeedType());<br><br>
        $em->persist($feed);<br>
        $em->flush();<br>
    }<br>
}<br>

But I am getting an error:
Integrity constraint violation: 1062 Duplicate entry '30-2' for key 'PRIMARY'

And there are really two inserts in the log:
INSERT INTO interview_scientificdirection (interview_id, scientificdirection_id) VALUES (?, ?) ([30,2])<br>
INSERT INTO interview_scientificdirection (interview_id, scientificdirection_id) VALUES (?, ?) ([30,2])<br>

scientificdirection is a Many to Many relation to the table after which we add the entity.
The whole thing happens in Sonata Admin and there this link is listed as:
-&gt;add('scientificDirections', 'sonata_type_model')

Answer the question

In order to leave comments, you need to log in

2 answer(s)
B
BoShurik, 2012-06-21
@nuclear

I did so.

class LogListener implements EventSubscriber
{
    private $container;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    public function getSubscribedEvents()
    {
        return array(Events::postUpdate, Events::postPersist, Events::preRemove);
    }

    public function postUpdate(LifecycleEventArgs $eventArgs)
    {
        $this->log($eventArgs, Log::ACTION_UPDATE);
    }

    public function postPersist(LifecycleEventArgs $eventArgs)
    {
        $this->log($eventArgs, Log::ACTION_PERSIST);
    }

    public function preRemove(LifecycleEventArgs $eventArgs)
    {
        $this->log($eventArgs, Log::ACTION_REMOVE);
    }

    private function log(LifecycleEventArgs $eventArgs, $action)
    {
        $token = $this->container->get('security.context')->getToken();
        if (!$token) {
            return;
        }

        $user = $token->getUser();
        if (!($user instanceof User)) {
            return;
        }

        $entity = $eventArgs->getEntity();
        if ($entity instanceof Log) {
            return;
        }

        $request = $this->container->get('request');

        $log = new Log();
        $log->setAction($action);
        $log->setUser($user);
        $log->setIp($request->server->get('REMOTE_ADDR'));
        $log->setEntityClass(get_class($entity));
        $log->setEntityId($entity->getId());

        $em = $this->container->get('doctrine')->getEntityManager();

        $meta = $em->getClassMetadata(get_class($log));
        $conn = $em->getConnection();

        foreach ($meta->getReflectionProperties() as $fieldName => $reflProp) {
            if (!$meta->isIdentifier($fieldName)) {
                $columns[] = $fieldName;
                $values[] = ':' . $fieldName;
            }
        }

        $insertSql = 'INSERT INTO ' . $meta->getQuotedTableName($conn->getDatabasePlatform())
            . ' (' . implode(', ', $columns) . ') '
            . 'VALUES (' . implode(', ', $values) . ')';

        $stmt = $conn->prepare($insertSql);

        $fields = $meta->getFieldNames();
        $association = $meta->getAssociationNames();

        foreach ($meta->getReflectionProperties() as $fieldName => $reflProp) {
            if (!$meta->isIdentifier($fieldName)) {
                $value = $reflProp->getValue($log);
                if (in_array($fieldName, $fields)) {
                    $mapping = $meta->getFieldMapping($fieldName);
                    $stmt->bindValue($meta->getColumnName($fieldName), $value, $mapping['type']);
                } else if (in_array($fieldName, $association)) {
                    $classMeta = $em->getClassMetadata($meta->getAssociationTargetClass($fieldName));
                    list($classId) = $classMeta->getIdentifier();

                    $mapping = $classMeta->getFieldMapping($classId);

                    $associationIdProperty = $classMeta->getReflectionProperty($classId);
                    $associationValue = $associationIdProperty->getValue($value);

                    $stmt->bindValue($meta->getColumnName($fieldName), $associationValue, $mapping['type']);
                } else {
                    throw new \Exception('Exception in log listener');
                }
            }
        }

        $stmt->execute();
    }
}

D
denver, 2012-05-09
@denver

Well, let's say that FeedEntity implements FeedItemInterface, then it will be an infinite loop, and it will only be executed twice because of the unique key. Yes, and it’s not right to flush in a persister - flush () starts and ends a large transaction, and I suspect that it’s not right to do this in the middle of the controller, at the moment of one of the persisters.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question