2016-02-22 1 views
0

Скажем, у меня есть таблицы A, B в классах сущностей MySQL и Doctrine с одинаковыми именами. Эти объекты управляются Doctrine и в основном создаются в соответствии с документами Symfony/Doctrine.Доступ к другим объектам при создании объекта Doctrine

Теперь я хочу создать сущность C со столбцами: x, y. Всякий раз, когда этот объект создан или обновлен, я хочу, чтобы установить значение столбцов:

  • х: SELECT COUNT (*) из А, где (некоторое условие)
  • у: выберите сумму (у) из В, где (другое условие)
  • тянуть некоторые другие данные из A или B и сохранить его в качестве значения столбца для C.

Я хочу сделать это в PHP, а не использовать MySQL триггеры. Я не могу добиться изнутри классов Entity, потому что у них нет доступа к диспетчеру сущностей. Я не хочу делать это в контроллере, так как я хочу, чтобы операции вставки/обновления были стандартизованы, и мне нужно будет делать это с нескольких контроллеров, и я вообще не думаю, что контроллер - хорошее место для логики, например это.

Так что нужен какой-то класс, который управляет сущности C.

Мой вопрос: Как я могу назвать этот менеджер класс и где я могу разместить его в Symfony? Я уверен, что это обычная потребность в Symfony (для доступа к нескольким объектам при создании другого объекта), но я не знаю, как это называется, и если с ними существует стандартная практика.

+0

использование DirectInjection компонент (DI), чтобы создать * сервис * - ввести doctrine.entitymanager услугу в он и доступ ко всем репозиториям по мере необходимости. – craigh

+0

Вы имели в виду Dependency Injection? Честно говоря, у меня есть чувство, что сущности субъекта не знают о менеджере сущности по причине. – Karolis

+1

Возможно, вам нужен слушатель доктрины: http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/events.html#lifecycle-events. Просто знайте, что это может быть немного сложной задачей. держите подобные вещи в синхронизации. Только отправляйтесь по этому маршруту, если вам действительно кажется, что вы не можете рассчитать необходимую информацию на лету. – Cerad

ответ

2

вы можете определить сервис в приложение/Config/services.yml и передать менеджер Entity в качестве аргумента

services: 
    app.service.some_service: 
     class: AppBundle\Service\SomeService 
     arguments: ["@doctrine.orm.default_entity_manager"] 

месту вашей логики внутри службы

use Doctrine\ORM\EntityManagerInterface; 
use AppBundle\Entity\SomeEntity; 

class SomeService 
{ 
    /** 
    * @var EntityManagerInterface 
    */ 
    protected $entityManager; 

    public function __construct(EntityManagerInterface $entityManager) { 
     $this->entityManager = $entityManager; 
    } 

    public function getSomeEntity($id) { 
     $entity = $this->entityManager->getRepository(SomeEntity::class); 
     // do some work, return result.. 

    } 
} 

вызова из контроллера

$someService = $this->get('app.service.some_service'); 
$someService->getSomeEntity($id); 

:)

+0

Это в основном то, что я пытался (плохо) сказать, выше. – craigh

+0

Проблема этого решения - «AppBundle \ Service \ SomeService». То, что я описал в вопросе, является обычной (стандартной) задачей, а 'SomeService' не является стандартным решением. Никто не знает, что делает служба, просто глядя на имя. В случае слушателя, я нахожу его более понятным. – Karolis

+0

@ Karolis Я считаю, что создание настраиваемого сервиса для любой задачи, более сложной, чем обновление одного значения (для которого это лучшее решение LifecycleCallbacks) является стандартным решением, imho. таким образом, у вас может быть вся логика - привязка к некоторой операции с несколькими объектами - в одном месте. btw, SomeService является просто заполнителем для вашего более описательного имени службы, поэтому «никто не знает ..» вообще не проблема;) – b3da

0

Я думаю, вам следует создать подписчика событий Doctrine как described in the documentation

Постараюсь объяснить основы.

1) Объявляет службу

services: 
    c_entity_counter_subscriber: 
    class: AppBundle\EventListener\CounterSubscriber 
    tags: 
     - { name: doctrine.event_subscriber, connection: default } 

2) в счете Абонента А и Б свойства

namespace AppBundle\EventListener; 

use Doctrine\Common\EventSubscriber; 
use Doctrine\ORM\Event\LifecycleEventArgs; 
use AppBundle\Entity\A; 
use AppBundle\Entity\B; 
use AppBundle\Entity\C; 

class CounterSubscriber implements EventSubscriber 
{ 
    public function getSubscribedEvents() 
    { 
    return array(
     'postPersist', 
     'postUpdate', 
    ); 
    } 

    public function postUpdate(LifecycleEventArgs $args) 
    { 
    $this->count($args); 
    } 

    public function postPersist(LifecycleEventArgs $args) 
    { 
    $this->count($args); 
    } 

    public function count(LifecycleEventArgs $args) 
    { 

    $entity = $args->getEntity(); 

    if (!$entity instanceof C) { 
     return; 
    } 

    $entityManager = $args->getEntityManager(); 
    // ... count/sum entities from A/B classes using $entityManager and update $entity 
    } 
} 
+0

В случае, если данные A, B и/или C извлекаются из разных подключений, возможно, вам нужно будет ввести «доктрина» в определении службы. – rodrigobb

+0

Как насчет производительности? Если я подписался на события postPersist/postUpdate, это также может повлиять на загрузку/гидратацию объекта (только потому, что есть слушатель, который необходимо загрузить)? – Karolis

+0

Не должно быть ухудшения производительности в декларации и загрузке слушателя/подписчика. И, когда вы проверяете '$ entity' экземпляр 'C', абонент вернется быстро. – rodrigobb

Смежные вопросы