S
S
Stanislav Romanov2014-10-27 19:15:26
symfony
Stanislav Romanov, 2014-10-27 19:15:26

Overall ranking for different entity types in symfony 2?

Hello.
The project uses symfony 2, doctrine.
There is a task to make a common rating for different types of entity through one common entity vote.
Simplified we see it like this:

/**
 * Flavi\AppBundle\Entity\Vote
 *
 * @ORM\Table(name="votes")
 * @ORM\Entity(repositoryClass="Flavi\AppBundle\Entity\VoteRepository")
 * @ORM\HasLifecycleCallbacks()
 * @JMS\ExclusionPolicy("none")
 */
class Vote {
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\Column(type="integer")
     */
    protected $userId;

    /**
     * @ORM\Column(type="integer")
     */
    protected $entityId;

    /**
     * @ORM\Column(type="string")
     */
    protected $entity;

    /**
     * @ORM\Column(type="integer")
     */
    protected $value;

    /**
     * @ORM\Column(type="datetime")
     */
    protected $createdAt;
}

The user votes +1 for, for example, entry with id = 2. A Vote is created in the table with fields: who voted (userId), for which entity (entity, entityId), how (value), and when (createdAt).
b92bd1476a65430480cc059620efe54f.png
Since this is a server-side API in the project, we use json serialization. It is not clear how to set up connections in doctrine so that the rating of an entity lies inside it and when serialized and would look something like this :
{entry: {
    id: 2,
    rating: 1,
    ...
}}

SOLUTION:
something like this
entity_subscriber:
          class: Flavi\AppBundle\EventListener\EntitySubscriber
          arguments:
              - "@doctrine.orm.entity_manager"
          tags:
              - { name: jms_serializer.event_subscriber }

<?php

namespace Flavi\AppBundle\EventListener;

use Doctrine\ORM\EntityManager;
use JMS\Serializer\EventDispatcher\Events;
use JMS\Serializer\EventDispatcher\EventSubscriberInterface;
use JMS\Serializer\EventDispatcher\ObjectEvent;

class EntitySubscriber implements EventSubscriberInterface
{
    protected $em;

    public function __construct(EntityManager $em)
    {
        $this->em = $em;
    }

    public static function getSubscribedEvents()
    {
        return array(
            array('event' => Events::POST_SERIALIZE, 'method' => 'onPostSerialize'),
        );
    }

    public function onPostSerialize(ObjectEvent $event)
    {
        //Добавляем рейтинг entity из таблицы votes
        $id = $event->getObject()->getId();
        $type = $event->getType()['name'];

        $qb = $this->em->getRepository('FlaviAppBundle:Vote')->createQueryBuilder('v');
        $qb->select('SUM(v.value) as rating');
        $qb->where('v.entity = :entity AND v.entityId = :entity_id');
        $qb->setParameter('entity', $type);
        $qb->setParameter('entity_id', $id);

        $result = $qb->getQuery()->getSingleScalarResult();

        if ($result !== NULL) {
            $event->getVisitor()->addData('rating', (integer) $result);
        }
    }
}

Answer the question

In order to leave comments, you need to log in

2 answer(s)
P
Pavel Hudinsky, 2014-10-27
@Kaer_Morchen

You will not be able to do this natively with the help of the doctrine in this case. Since you will not create connections between Vote and other entities!
I see this solution: since you are using JMSSerializerBundle to serialize entities, you can set up a subscriber that will check the type of the entity on pre_serialize, get a rating for it and add it to the serialization result.
You can read more about this here

B
BoShurik, 2014-10-27
@BoShurik

I would make a VotableInterface with a setRating method and when saving the Vote, recalculate the rating for the entity that was voted for

interface VotableInterface
{
    public function setRating($rating);
}

class Object implements VotableInterface
{
    /**
     * @ORM\Column(type="integer")
     */
    private $rating;

    public  function setRating($rating)
    {
        $this->rating = $rating;
    }

    public function getRating()
    {
        return $this->rating;
    }
}

class VoteListener
{
    public function postPersist(LifecycleEventArgs $event)
    {
        $vote = $event->getEntity();
        if (!$vote instanceof Vote) {
            return;
        }
        /**
         * @var Object $entity
         */
        $entity = $vote->getEntityObject();
        if (!$entity instanceof VotableInterface) {
            // Exception
        }
        $entity->setRating($entity->getRating() + $vote->getValue());

        // Update $entity
    }
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question