1

I want to create some virtual properties for an entity in an n:m relation.

I have an User, an Achievment and an AchievementUser entity. The value an user have in an Achievement is stored in the field value in the entity AchievementUser.

User -------- 1:n -------- AchievementUser -------- n:1 -------- Achievement
name:String                value:Integer                         name:String
[...]                                                            [...]

Now I want to return the value an user have in an achievement with the achievement itself. So I need a virtual property and a method getValue() in the Achievement entity, but to get the corresponding AchievementUser object, I need the ID of the current logged in user.

How can I get this? Or is there an other possiblility to get the user value for an achievement? Thanks for your help!

Edit: I only have an API based application. Only the serializer executes the Getter method. Here is the content of my serializer file:

virtual_properties:
    getValue:
        serialized_name: value
        type: integer
        groups: ['achievement_default']
mgluesenkamp
  • 529
  • 6
  • 19
  • Isn't this a classic [many-to-many](http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#many-to-many-bidirectional) (with the join table AchievementUser)? How did you define the relations, any code?. Cause in a many to many one could get the user by current user ID and then with doctrine magic basically just access the relation property (like eg.: `user->getAchievements()`) – Jenne May 29 '17 at 14:11

1 Answers1

5

You can implement a method in the Achievement entity and pass the current authenticated user into it from your controller of twig template.

use Doctrine\Common\Collections\Criteria;

// ...

/**
 * @return Collection
 */
public function getAchievementUsers(User $user)
{
    $criteria = Criteria::create()->where(Criteria::expr()->eq('user', $user));

    return $this->achievementUsers->matching($criteria);
}

In case of using a JMS serializer, you can add a virtual field and fill it with data using getAchievementUsers method by defining a serialization listener and injecting the TokenStorage to retrieve the current authenticated user.

<?php

namespace AppBundle\Listener\Serializer;

...
use JMS\Serializer\GenericSerializationVisitor;
use JMS\Serializer\EventDispatcher\ObjectEvent;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;

class AchievementSerializerListener
{
    /**
     * @var User
     */
    protected $currentUser;

    /**
     * @param TokenStorage $tokenStorage
     */
    public function __construct(TokenStorage $tokenStorage)
    {
        $this->currentUser = $tokenStorage->getToken()->getUser();
    }

    /**
     * @param ObjectEvent $event
     */
    public function onAchievementSerialize(ObjectEvent $event)
    {
        if (!$this->currentUser) {
            return;
        }

        /** @var Achievement $achievement */
        $achievement = $event->getObject();

        /** @var GenericSerializationVisitor $visitor */
        $visitor = $event->getVisitor();

        $visitor->setData(
            'achievement_users',
            $achievement->getAchievementUsers($this->currentUser)
        );
    }
}

services.yml

  app.listener.serializer.achievement:
        class: AppBundle\Listener\Serializer\AchievementSerializerListener
        arguments:
          - '@security.token_storage'
        tags: [ { name: jms_serializer.event_listener, event: serializer.post_serialize, class: AppBundle\Entity\Achievement, method: onAchievementSerialize } ]
Mikhail Prosalov
  • 4,155
  • 4
  • 29
  • 41
  • The problem is that I only have a API based app. So only the serializer uses the get method. I added additional informations about my app. Is it possible to define a parameter there? – mgluesenkamp May 29 '17 at 14:37
  • Updated my answer. Hope it will help you to achieve your goal. – Mikhail Prosalov May 29 '17 at 14:55
  • @MikhailProsalov Unfortunately the answer does not work. The property will always be an empty `{}`. Please see this question: https://stackoverflow.com/questions/45441456/jms-virtualproperty-with-argument-and-custom-listener-subscriber Can you help me please? – StockBreak Aug 01 '17 at 15:32