如何将 EntityManager 访问到 RabbitMQBundle 自定义生产者 class?

How to access EntityManager into a RabbitMQBundle custom producer class?

我在 Symfony 2.8 项目中使用 RabbitMQBundle,我想使用自定义生成器 class,它在发布 RabbitMQ 消息之前在数据库中保留一个实体(消息)。

我在 config.yml 中定义了自定义生产者 class:

old_sound_rabbit_mq:
  ...
  producers:
    myproducer:
      class: AppBundle\Services\GenericProducer
      connection: default
      exchange_options: {name: 'my_exchange', type: direct}

自定义制作人class:

<?php

namespace AppBundle\Services;

use AppBundle\Entity\Message;
use OldSound\RabbitMqBundle\RabbitMq\Producer;

/**
 * Customised Producer, that publishes AMQP Messages
 * but also:
 * - writes an entry in the Message table
 */
class GenericProducer extends Producer
{
    /**
     * Entity Manager
     */
    protected $em;


    public function setEntityManager($entityManager)
    {
        $this->em = $entityManager;

        return $this;
    }

    /**
     * Publishes the message and merges additional properties with basic properties
     * And also:
     * - writes an entry in the Message table
     *
     * @param string $action
     * @param array $parameters
     * @param string $routingKey
     * @param array $additionalProperties
     * @param array|null $headers
     */
    public function publish($action, $parameters = array() , $routingKey = '', $additionalProperties = array(), array $headers = null)
    {
        $message = new Message();
        $message->setAction($action)
            ->setParameters($parameters);
        $this->em->persist($message);
        $this->em->flush();

        $msgBody = array(
            'action' => $action,
            'parameters' => $parameters
        );
        parent::publish($msgBody, $routingKey, $additionalProperties, $headers);
    }
}

我如何调用 GenericProducer->setEntityManager,因为生产者未在 services.yml 中定义,就像其他服务一样?

还有其他方法可以实现吗?

感谢您的宝贵时间。

生产者服务定义由 Dependency Injection Extension of the bundle 中的包动态生成。

您可以尝试 decorate the existing service or create a compiler pass 获取现有服务并通过调用 setEntityManager 函数扩展它。

根据@lordrhodos 的建议,我装饰了由 RabbitMQBundle 生成的生产者服务。这是完整的代码:

config.yml(没什么特别的):

old_sound_rabbit_mq:
  ...
  producers:
    myproducer:
      connection: default
      exchange_options: {name: 'my_exchange', type: direct} 

services.yml(这里定义了一个装饰服务):

app.decorating_myproducer_producer:
      class: AppBundle\Services\GenericProducer
      decorates: old_sound_rabbit_mq.myproducer_producer
      arguments: ['@
app.decorating_myproducer_producer.inner', '@doctrine.orm.entity_manager']
      public: false

装饰器class:

<?php

namespace AppBundle\Services;

use AppBundle\Entity\Message;
use OldSound\RabbitMqBundle\RabbitMq\Producer;

/**
 * Customised Producer, that publishes AMQP Messages
 * but also:
 * - writes an entry in the Message table
 */
class GenericProducer extends Producer
{
    /**
     * @var Producer
     */
    protected $producer;

    /**
     * @var EntityManager
     */
    protected $em;

    /**
     * GenericProducer constructor.
     * @param Producer $producer
     * @param EntityManager $entityManager
     */
    public function __construct(Producer $producer, EntityManager $entityManager)
    {
        $this->producer = $producer;
        $this->em = $entityManager;
    }


    /**
     * Publishes the message and merges additional properties with basic properties
     * And also:
     * - writes an entry in the Message table
     *
     * @param string $action
     * @param array $parameters
     * @param string $routingKey
     * @param array $additionalProperties
     * @param array|null $headers
     */
    public function publish($action, $parameters = array() , $routingKey = '', $additionalProperties = array(), array $headers = null)
    {
        $message = new Message();
        $message->setAction($action)
            ->setParameters($parameters);
        $this->em->persist($message);
        $this->em->flush();

        $msgBody = array(
            'action' => $action,
            'parameters' => $parameters
        );
        $this->producer->publish(serialize($msgBody), $routingKey, $additionalProperties, $headers);

    }
}

最后,从控制器调用原始生产者:

$this->get('old_sound_rabbit_mq.myproducer_producer')->publish('wait', ['time' => 30]);