1
votes

I'm using the Gedmo SoftDeletable filter for Symfony2 and Doctrine (https://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/softdeleteable.md)

I'm also using the JMSSerializerBundle to serialize reponses to JSON for my REST API.

How to tell jms serializer annotation group about softdeleteable filters ?

And when my response contain entity which have relation with entity which have deleted_at field not empty I have error

Entity of type 'AppBundle\Entity\Courses' for IDs id(2) was not found

because sub_cources, example id 1 have relation with courses in example id 2 and courses with id 2 have not empty deleted_at - removed entity

example I have

/**
 * @ORM\HasLifecycleCallbacks
 * @ORM\Table(name="sub_cources")
 *@ORM\Entity(repositoryClass="AppBundle\Entity\Repository\SubCoursesRepository")
 * @Gedmo\SoftDeleteable(fieldName="deletedAt")
 * @AssertBridge\UniqueEntity(
 *     groups={"post_sub_course", "put_sub_course"},
 *     fields="name",
 *     errorPath="not valid",
 *     message="This name is already in use."
 * )
 */
class SubCourses


    /**
 * @var Courses
 *
 * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Courses", inversedBy="subCourses")
 * @Annotation\Groups({
 *     "get_sub_courses"
 * })
 * @Annotation\Type("AppBundle\Entity\Courses")
 */
private $courses;

my action

            return $this->createSuccessResponse(
            [
                'sub_courses' => $subCourses->getEntitiesByParams($paramFetcher),
                'total' => $subCourses->getEntitiesByParams($paramFetcher, true),
            ],
            ['get_sub_courses'],
            true
        );

And my response look like

    /**
 * @param $data
 * @param null|array $groups
 * @param null|bool  $withEmptyField
 *
 * @return View
 */
protected function createSuccessResponse($data, array $groups = null, $withEmptyField = null)
{
    $context = SerializationContext::create()->enableMaxDepthChecks();
    if ($groups) {
        $context->setGroups($groups);
    }

    if ($withEmptyField) {
        $context->setSerializeNull(true);
    }

    return View::create()
        ->setStatusCode(self::HTTP_STATUS_CODE_OK)
        ->setData($data)
        ->setSerializationContext($context);
}

How to tell jms serializer annotation group about softdeleteable filters ?

1

1 Answers

3
votes

The solution to this issue that I used was to use the serializer events for pre and post serialization.

The first thing I did was have my entity implement the \Gedmo\SoftDeleteable\SoftDeleteable interface.

I created a container-aware listener and on the pre serialize event, checked to see if the object was soft-deleteable. if it was, then I disabled the soft deletable filter. In post serialization, I make sure the filter is turned back on.

This only works for lazy-loaded/proxy relationships. if your relationship fetch is set to EAGER, this will NOT work

Subscriber class:

<?php
namespace AppBundle\Event\Subscriber;

use Gedmo\SoftDeleteable\SoftDeleteable;
use JMS\Serializer\EventDispatcher\EventSubscriberInterface as JmsEventSubscriberInterface;
use JMS\Serializer\EventDispatcher\ObjectEvent;
use Symfony\Component\DependencyInjection\ContainerInterface;

class JsonSerializerSubscriber implements JmsEventSubscriberInterface, EventSubscriberInterface
{
    /**
     * @var ContainerInterface
     */
    protected $container;

    public static function getSubscribedEvents()
    {
        return [
            [
                'event' => 'serializer.pre_serialize',
                'method' => 'onPreSerialize',
            ],
            [
                'event' => 'serializer.post_serialize',
                'method' => 'onPostSerialize',
            ],
        ];
    }

    public function onPreSerialize(ObjectEvent $objectEvent)
    {
        // before serializing; turn off soft-deleteable
        $object = $objectEvent->getObject();
        if ($object instanceof SoftDeleteable) {
            $em = $this->container->get('doctrine.orm.default_entity_manager');
            if ($em->getFilters()->isEnabled('softdeleteable')) {
                $em->getFilters()->disable('softdeleteable');
            }
        }
    }

    public function onPostSerialize(ObjectEvent $objectEvent)
    {
        // after serializing; make sure that softdeletable filter is turned back on
        $em = $this->container->get('doctrine.orm.default_entity_manager');
        if (!$em->getFilters()->isEnabled('softdeleteable')) {
            $em->getFilters()->enable('softdeleteable');
        }
    }

    /**
     * @param ContainerInterface $container
     */
    public function setContainer(ContainerInterface $container)
    {
        $this->container = $container;
    }
}

services.xml:

<services>
...
    <service id="my.serializer.event_subscriber" class="AppBundle\Event\Subscriber\JsonSerializerSubscriber">
         <call method="setContainer">
             <argument type="service" id="service_container"/>
         </call>
         <tag name="jms_serializer.event_subscriber" />
     </service>
...
</services>

Entity class (using op's example):

class SubCourses implements \Gedmo\SoftDeleteable\SoftDeleteable
{
...
}