ZF2 - Doctrine ORM,简单表连接

Posted

技术标签:

【中文标题】ZF2 - Doctrine ORM,简单表连接【英文标题】:ZF2 - Doctrine ORM, Simple Table Join 【发布时间】:2014-05-05 08:40:34 【问题描述】:

我目前正在学习如何将 Doctrine ORM 与 ZF2 一起使用,目前我的目标是从简单的表连接中检索数据并将其显示到屏幕上。

我已经阅读了文档,看起来很简单。

这些是我的桌子:

user
------------------------
|user_id | name | email   |
--------------------------
| 1      | John | j@b.com |
--------------------------
| 2      | Bob  | b@j.com |
--------------------------

user_role_linker
--------------------------
|user_id | role_id        |
--------------------------
| 1      | administrator  |
--------------------------
| 2      | staff          |
--------------------------

我想要实现的是我的观点列表如下:

ID       Name       Email      Role              Actions
--------------------------------------------------------
1        John       j@b.com    Administrator     Edit
2        Bob        b@j.com    Staff             Edit
--------------------------------------------------------
Paging goes here
----------------

这是我目前拥有的,它似乎可以工作,除了我不确定如何获取连接的表数据:

User entity::

<?php
    namespace Administration\Entity;
    use Doctrine\ORM\Mapping as ORM;
    use Doctrine\ORM\Mapping\ManyToMany;
    use Doctrine\ORM\Mapping\JoinTable;
    use Doctrine\ORM\Mapping\JoinColumn;
    use Doctrine\Common\Collections\ArrayCollection;

    /** @ORM\Entity */

    class User 
        /**
         * @ORM\Id
         * @ORM\GeneratedValue(strategy="AUTO")
         * @ORM\Column(type="integer",name="user_id")
         */

        protected $user_id;

        /** @ORM\Column(type="integer", name="parent_id") */
        protected $parent_id;

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

        /** @ORM\Column(type="string", name="email") */
        protected $email;

        //Setters and getters

        public function getUserId() 
            return $this->user_id;
        

        public function setName($name) 
            $this->name = $name;
        

        public function getName() 
            return $this->name;
        

        public function getEmail() 
            return $this->email;
        

        public function setEmail($email) 
            $this->email = $email;
        

        /**
        * @ManyToMany(targetEntity="UserRoleLinker")
        * @JoinTable(
        * name="user_role_linker",
        * joinColumns=
        *   @JoinColumn(
        *     name="user_id",
        *     referencedColumnName="id")
        *  ,
        * inverseJoinColumns=
            *   @JoinColumn(
             *     name="user_id",
             *     referencedColumnName="id",
             *     unique=true)
             * )
        */
        private $role_id;

        public function __construct()
        
            $this->role_id = new ArrayCollection();
        

        /** @return Collection */
        public function getRoleId()
        
            return $this->role_id;
        

    

用户角色链接器实体::

 <?php
    namespace Administration\Entity;
    use Doctrine\ORM\Mapping as ORM;

/** @ORM\Entity */
class UserRoleLinker 
    /**
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     * @ORM\Column(type="integer",name="user_id")
     */
    protected $user_id;

    /** @ORM\Column(type="string", name="role_id") */
    protected $role_id;

    /** @param User|null */
    public function getRoleId() 
       return $this->role_id;
    

我的管理控制器::

public function usersAction() 
   $em = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
   $userFunctions = new UserFunction($em);
   $userArray = $userFunctions->getUsers();
   $viewModel = new ViewModel(array('users' => $userArray));
   return $viewModel;

这调用了我的 UserFunctions 类::

public function getUsers()

    //This function returns the users
    return $this->em->getRepository('Administration\Entity\User')->findAll();

在我看来,我列出的数据如下:

<?php
    foreach ($this->users AS $user) 
?>
<tbody>
<tr class="odd gradeX">
    <td ><?php  echo $user->getUserId(); ?></td>
    <td><?php echo $user->getName(); ?></td>
    <td><?php echo $user->getEmail(); ?></td>
    <td class="center">*** HOW DO I SHOW THE ROLE ?? ***</td>
    <td>Edit</td>
</tr>
<?php  ?>

如何获取要在视图中显示的角色?

【问题讨论】:

在这里查看关联映射:docs.doctrine-project.org/en/2.0.x/reference/… 【参考方案1】:

您必须在实体定义中定义用户和角色之间的正确关系。 我不确定你为什么在这里使用链接器表。您是否真的想在用户和角色之间建立多对多关系(每个用户都可以有多个角色?)。 如果不是,您可以轻松地将角色 ID 移动到用户表中,然后在用户和角色之间定义 ManyToOne 关系。

您的用户表将如下所示:

-------------------------------------------
|user_id | name | email   | role_id       |
-------------------------------------------
| 1      | John | j@b.com | administrator |
-------------------------------------------
| 2      | Bob  | b@j.com | staff         |
-------------------------------------------

我建议以用户为拥有方查看ManyToOne。您可以在the Doctrine2 documentationthe Doctrine2 documentation

中检查如何在实体定义中正确定义单向多对一关系

之后,您可以在视图中简单地调用$user-&gt;getRole();...

编辑

使用连接表修复一对多的答案:

这在doctrine documentation here...中也有描述

你需要三张桌子;一个用户表、一个角色表和一个用户角色链接器表 用户是实体,角色是实体,角色链接器表在您的情况下不是实体。您应该删除该实体,链接器表仅用于连接数据库中的用户和角色。

用户表

---------------------------
|id      | name | email   |
---------------------------
| 1      | John | j@b.com |
---------------------------
| 2      | Bob  | b@j.com |
---------------------------

角色表

-----------------
| id            |
-----------------
| administrator |
-----------------
| staff         |
-----------------
| guest         |
-----------------
| another role  |
-----------------

链接器表

--------------------------
|user_id | role_id       |
--------------------------
| 1      | administrator |
--------------------------
| 2      | staff         |
--------------------------

在您的用户实体中:

/** ONE-TO-MANY UNIDIRECTIONAL, WITH JOIN TABLE ONLY WORK WITH MANY-TO-MANY ANNOTATION AND A UNIQUE CONSTRAINT
  * @ORM\ManyToMany(targetEntity="Administration\Entity\Role")
  * @ORM\JoinTable(name="user_role_linker",
  *      joinColumns=@ORM\JoinColumn(name="user_id", referencedColumnName="id"),
  *      inverseJoinColumns=@ORM\JoinColumn(name="role_id", referencedColumnName="id", unique=true)
  *      )
  */
protected $roles;

/**
 * Get roles.
 *
 * @return ArrayCollection
 */
public function getRoles()

    return $this->roles;


/**
 * Add a role to the user.
 *
 * @param Role $role
 *
 * @return User
 */
public function addRole(Role $role)

    $this->roles[] = $role;

    return $this;


/**
 * Remove a role from the user
 *
 * @param Role $role
 *
 * @return User
 */
public function removeRole(Role $role)

    $this->roles->removeElement($role);

    return $this;

你的角色实体:

/**
 * An example entity that represents a role.
 *
 * @ORM\Entity
 * @ORM\Table(name="role")
 * @property string $id
 */
class Role

    /**
     * @var string
     * @ORM\Id
     * @ORM\Column(type="string", length=255, unique=true, nullable=false)
     */
    protected $id;

    /**
     * Get the id.
     *
     * @return string
     */
    public function getId()
    
        return $this->id;
    

我认为这应该可以帮助您解决它...

也许您应该将以下内容添加到您的应用程序模块中:

public function doctrineValidate(MvcEvent $event)
    $application = $event->getParam('application');
    $serviceManager = $application->getServiceManager();
    $entityManager = $serviceManager->get('doctrine.entitymanager.orm_default');
    $validator = new SchemaValidator($entityManager);
    $errors = $validator->validateMapping();
    if (count($errors) > 0) 
        // Lots of errors!
        var_dump($errors);
    

然后在引导中:

$eventManager->attach('dispatch', array($this, 'doctrineValidate'));

在模块中: Doctrine 将通过检查您的实体定义来帮助您。它可能会提前告诉您实体定义中有问题...

【讨论】:

【参考方案2】:

这令人困惑,但正如您在实体中定义的那样,您可以使用 User 实体 getRoleId 的函数获取角色集合。然后,对于每个 UserRoleLinker 实体,您必须再次使用 getRoleId 函数,该函数将返回“Administrator”或“Staff”字符串。循环示例:

$roles = $user->getRoleId();

foreach ( $roles as $role ) 
    $roleId = $role->getRoleId();

我建议你换一种方式。一个实体应该是User,具有一个名为roles 的属性。另一方面,您可以拥有实体 Role。它们之间的链接应该是One-To-Many, Unidirectional with Join Table(即 user_role_linker 表)。

【讨论】:

我已尝试使用您的建议使其正常工作,请查看我添加的答案...收到一些不寻常的通知,对象也没有获得所需的信息。【参考方案3】:

正如 lluisaznar 所建议的(虽然我需要多对一的关系,因为每个用户只有一个角色)。

我正在尝试以下方法:

<?php
    namespace Administration\Entity;
    //use stuff

    /** @ORM\Entity */

    class User 
        /**
         * @ORM\Id
         * @ORM\GeneratedValue(strategy="AUTO")
         * @ORM\Column(type="integer",name="user_id")
         */

        //setters getters

/**
 * @ManyToOne(targetEntity="Role")
 * @JoinColumn(name="user_id", referencedColumnName="id")
 */
        private $role;

        public function __construct()
        
            $this->role = new ArrayCollection();
        

        /** @return Collection */
        public function getRoleId()
        
            return $this->role;
        

    

以及角色实体:

<?php
namespace Administration\Entity;
use Doctrine\ORM\Mapping as ORM;

/** @ORM\Entity */
class Role 
    /**
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     * @ORM\Column(type="integer",name="user_id")
     */
    protected $user_id;

    /** @ORM\Column(type="string", name="role_id") */
    protected $role;

    /** @param User|null */
    public function getRoleId() 
       return $this->role;
    



当我运行它时,我会收到以下通知:

Notice: Undefined index: id in trunk/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php on line 2611

Notice: Undefined index: user_id in trunk/vendor/doctrine/common/lib/Doctrine/Common/Proxy/AbstractProxyFactory.php on line 121

角色也没有被显示,当我将 $user 对象转储到角色下时,我得到了这个:

 private 'role' => 
    object(DoctrineORMModule\Proxy\__CG__\Administration\Entity\Role)[609]
      public '__initializer__' => 
        object(Closure)[595]
      public '__cloner__' => 
        object(Closure)[596]
      public '__isInitialized__' => boolean false
      protected 'user_id' => null
      protected 'role' => null

【讨论】:

如果您有ManyToOne 关系,则不需要链接器表。删除链接器表并将role_id 列添加到您的用户表。查看我的答案了解更多详情。 是的 - 这是我通常会做的事情。不幸的是,链接器表是 BjyAuthorize / ZFCUser 的一部分,并且每次更新第三方模块时都无法在不请求麻烦的情况下将其删除。通常我会做一个简单的 sql 连接,而不会三思而后行……似乎 ORM 中的一个简单连接需要火箭科学的 PHD! :) 没有一个简单的连接只是一个简单的连接:) 如果我今天晚些时候有时间我会看看你的代码并帮助你。现在问题出在哪里?还是同样的问题? 谢谢威尔特,将不胜感激。我可以通过标准实体访问数据库。我苦苦挣扎的地方是如何连接两个表(例如上面的)并将所需的信息返回到视图。理想情况下,我想在其中添加分页,但是我认为在考虑分页之前我需要先了解连接。 成功了吗?

以上是关于ZF2 - Doctrine ORM,简单表连接的主要内容,如果未能解决你的问题,请参考以下文章

跨数据库连接原则

Doctrine2 ORM 访问多对多连接表

ZF2 Skeleton 和 Doctrine ORM xml 模式合并

Zend/Doctrine 不能执行 ORM 操作,表已经存在

ZF2 + Composer + Jelastic 中的教义

Doctrine2:任意连接和单表继承