Symfony 2.0在实体内部获得服务

Kam*_*ari 36 php service entity symfony doctrine-orm

我正在搜索,无法找到答案.我的应用程序中有数据库角色模型.用户可以拥有角色,但必须将此角色存储到数据库中.

但是,用户需要从数据库中添加默认角色.所以我创建了一个服务:

<?php

namespace Alef\UserBundle\Service;

use Alef\UserBundle\Entity\Role;

/**
 * Description of RoleService
 *
 * @author oracle
 */
class RoleService {

    const ENTITY_NAME = 'AlefUserBundle:Role';

    private $em;

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

    public function findAll()
    {
        return $this->em->getRepository(self::ENTITY_NAME)->findAll();
    }

    public function create(User $user)
    {
        // possibly validation here

        $this->em->persist($user);
        $this->em->flush($user);
    }

    public function addRole($name, $role) {
        if (($newrole = findRoleByRole($role)) != null)
            return $newrole;
        if (($newrole = findRoleByName($name)) != null)
            return $newrole;

        //there is no existing role
        $newrole = new Role();
        $newrole->setName($name);
        $newrole->setRole($role);

        $em->persist($newrole);
        $em->flush();

        return $newrole;
    }

    public function getRoleByName($name) {
        return $this->em->getRepository(self::ENTITY_NAME)->findBy(array('name' => $name));
    }

    public function getRoleByRole($role) {
        return $this->em->getRepository(self::ENTITY_NAME)->findBy(array('role' => $role));
    }

}
Run Code Online (Sandbox Code Playgroud)

services.yml是:

alef.role_service:
    class: Alef\UserBundle\Service\RoleService
    arguments: [%doctrine.orm.entity_manager%]
Run Code Online (Sandbox Code Playgroud)

现在我想在两个地方使用它: UserControllerUser实体.我怎样才能让他们进入实体?至于控制器我认为我只需要:

$this->get('alef.role_service');
Run Code Online (Sandbox Code Playgroud)

但如何获得实体内部的服务?

Cer*_*rad 43

你没有.这是一个非常常见的问题.实体应仅了解其他实体,而不了解实体经理或其他高级服务.向这种发展方式过渡可能是一个挑战,但通常是值得的.

您要做的是在加载用户时加载角色.通常情况下,您最终会使用UserProvider执行此类操作.您是否阅读了有关安全性的章节?那应该是你的出发点:

http://symfony.com/doc/current/book/security.html


Kai*_*Kai 25

虽然将服务转换为实体非常气馁,但一种很好的方法可以解决这个问题,而不会涉及到全局内核.

Doctrine实体具有可以挂钩事件监听器的lifeCycle事件,请参阅http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html#lifecycle-events 为了例如,我将使用postLoad,它在创建实体后很快触发.

EventListeners 可以作为您注入其他服务的服务.

添加到app/config/config.yml:

services:
     example.listener:
           class: Alef\UserBundle\EventListener\ExampleListener
     arguments:
           - '@alef.role_service'
     tags:
           - { name: doctrine.event_listener, event: postLoad }
Run Code Online (Sandbox Code Playgroud)

添加到您的实体:

 use Alef\UserBundle\Service\RoleService;

 private $roleService;

 public function setRoleService(RoleService $roleService) {
      $this->roleService = $roleService;
 }
Run Code Online (Sandbox Code Playgroud)

并添加新的EventListener:

namespace Alef\UserBundle\EventListener;

use Doctrine\ORM\Event\LifecycleEventArgs;
use Alef\UserBundle\Service\RoleService;

class ExampleListener
{
     private $roleService;

     public function __construct(RoleService $roleService) {
         $this->roleService = $roleService;
     }

     public function postLoad(LifecycleEventArgs $args)
     {
         $entity = $args->getEntity();
         if(method_exists($entity, 'setRoleService')) {
             $entity->setRoleService($this->roleService);
         }
     }
}
Run Code Online (Sandbox Code Playgroud)

  • 这是问题的最佳解决方案和最准确的答案.我讨厌"你不能"这样的答案,"这是错误的设计模式"或"它会破坏一切,你这个白痴!" 由大师写的什么都没有."更糟糕的是(有时)更好";)再次感谢. (8认同)
  • 可悲的是,"错误的设计模式","MCV模型","单独的业务层"等等.当"老板"想要"现在"完成这件事时,会走出窗外.感谢@Kai的回答,这正是我想要的. (7认同)
  • 在`EventListener` 的情况下,我不喜欢它为你拥有的每个实体调用它。 (3认同)