如何使用symfony 2和doctrine管理ManyToOne关系

时间:2016-01-16 12:14:21

标签: php symfony orm doctrine

我目前正在发现symfony 2,并在这个精彩的框架上训练自己。所以我有新手问题......

我遵循本教程以管理与学说的关系: http://symfony.com/doc/current/book/doctrine.html

嗯,在我的测试中,我有一个问题和一个问题。

首先是问题: Symphony最佳实践表明,在其他.orm.yml文件中使用注释进行学说映射而不是yaml会更好。好,我完全赞同。 “使用注释很方便,并允许您在同一文件中定义所有内容”。因此,如果我们选择使用注释,我想我们不再需要.orm.yml映射文件了? 假设我有一个名为userType的表。我创建了一个实体类userType.php,并在此类中直接添加了带注释的映射信息。我尝试的任何东西,添加声明:

use Doctrine\ORM\Mapping as ORM;

或不在我的userType.php类中,symfony显示此错误:

No mapping file found named 'UserType.orm.yml' for class 'AppBundle\Entity\UserType

如果我不创建UserType.orm.yml文件。

所以这是我的问题:如果我们选择只使用注释,我们还需要一个.orm.yml映射文件吗?如果是,我们必须在此文件中添加的最小信息是什么?

第二点我的问题: 我的用户角色位于与用户表不同的表(userType)中。

+-------------------------------------------+-------------------------------------------+
|user                                       |   userType                                |
|id    username    password    userType_id  |   userType_id  label          role        |
|1     testuser    something   1            |   1            Administrator  ROLE_ADMIN  |
+-------------------------------------------+-------------------------------------------+

所以我想我需要在user.php实体类中添加manyToOne关系(许多用户只能拥有相同的一个角色)。

所以我在User.orm.yml映射文件中添加了这些行

(…)
manyToOne:
        userType:
            targetEntity: UserType
            joinColumn:
                name: userType_id
                referencedColumnName: userType_id
    lifecycleCallbacks: {  }
(…)

并在我的user.php实体类中声明了var userType,如下所示

/**
*
*/
private $userType;

这是我的userType.php实体类文件:

    namespace AppBundle\Entity;

    use Doctrine\ORM\Mapping as ORM;

    /**
     * @ORM\Entity
     */
    class UserType
    {
        /**
         * @ORM\Id
         * @ORM\Column(type="integer", name="userType_id")
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        private $id;

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


        /**
         * @ORM\Column(type="simple_array", name="role")
         */
        private $role;


        public function getId()
        {
            return $this->id;
        }

        /**
         *
         */
        public function getLabel()
        {
            return $this->label;
        }
        public function setLabel($label)
        {
            $this->label = $label;
        }

        /**
         *
         */
        public function getRole()
        {
            return $this->role;
        }
        public function setRole($role)
        {
            $this->role = $role;
        }
}

我的UserType.orm.yml文件:

AppBundle\Entity\UserType:
    type: entity
    table: userType
    id:
        id:
            type: integer
            id: true
            column: userType_id
            generator:
                strategy: AUTO
    fields:
        label:
            type: string
            length: '150'
            column: label
        role:
            type: simple_array
            length: '100'
            column: role
    lifecycleCallbacks: {  }

好吧,我的user.php实体的$ userType var似乎是一个包含userType数据的对象。 但是,如果我做了

var_export($this->userType, true);
$ userType对象的

我得到了这个:

Proxies\__CG__\AppBundle\Entity\UserType::
__set_state(array( '__initializer__' => Closure::
__set_state(array( )), '__cloner__' =>
Closure::__set_state(array( )), '__isInitialized__' =>
false, 'id' => 1, 'label' => NULL, 'role' => NULL, ))

仅填充字段ID,其他为NULL。 如何在对象$ userType中获取标签和角色字段值?我的错是什么?

非常感谢你的帮助。

2 个答案:

答案 0 :(得分:1)

感谢您的建议。他们帮助了我很多。

我解决了我的两个麻烦。

对于我的.orm文件问题:确实正如@chalasr建议的那样,在删除Resources / config / doctrine文件夹之后,Symphony停止向我显示有关缺少.orm文件的错误。通过关注@chalasr其他技巧,我设法停止使用orm文件。感谢。

但我还有其他问题(只有“id”字段填入$ userType对象,其他地方为NULL)。 我注意到$ userType对象没有初始化,实际上它是一个学说“lazy-loading-issue”。

这2个帖子帮助我解决了我的问题:

Get entities from a unidirectional many to many relation with Doctrine2 and Symfony2

doctrine2 association is not initialized

我在我的ManyToOne关系中添加了选项fetch =“EAGER”,现在所有$ userType对象字段都已完全填充。

这是我实际的ManyToOne关系(用注释制作; - ))

/**
     * @ORM\ManyToOne(targetEntity="UserType", fetch="EAGER")
     * @ORM\JoinColumn(name="users_types_id", referencedColumnName="users_types_id")
     */
    private $userType;

这就是我如何获得角色字段值

/**
     * Returns the roles or permissions granted to the user for security.
     */
    public function getRoles()
    {

        $accessor_user_role = PropertyAccess::createPropertyAccessor();

        $roles = $accessor_user_role->getValue($this->userType, 'role');

        // guarantees that a user always has at least one role for security
        if (empty($roles)) {
            $roles[] = 'ROLE_USER';
        }

        return $roles;
    }

我希望通过这种方式来尊重Symfony的良好做法。

非常感谢你的帮助。

答案 1 :(得分:0)

不,你必须在这两种格式之间做出选择。

您的实体存在许多问题。

您已省略@ORM\Table语句,请使用:

/**
 * @ORM\Entity
 * @ORM\Table(name="user_types")
 */
class UserType
{
    //...
}

然后,您必须重命名与其包含的类名称对应的文件。

您的班级名为UserType,但包含该班级的文件名为userType.php 根据{{​​3}}

,您必须使用UserType.php
  

从文件系统加载时,每个命名空间分隔符都转换为DIRECTORY_SEPARATOR   [...]
  从文件系统加载时,完全限定的命名空间和类后缀为.php。

示例:App\AcmeBundle\Entity\User将变为src/App/AcmeBundle/Entity/User.php

另外,我认为你在实体的声明中省略了命名空间的一部分,添加了bundle命名空间中缺少的第一部分(如PSR所述,它应该是{{1}之间的第一个文件夹的名称和你的src目录。)

如果您在使用注释之前已开始使用YAML,请执行以下过程:

  • 删除捆绑包的整个AppBundle目录(或仅删除与实体对应的映射文件)。
  • 使用Resources/config/doctrine
  • 清除实体元数据的缓存
  • 使用php app/console doctrine:cache:clear-metadata
  • 清除应用程序缓存

执行此操作后,通过执行以下操作,使用正确的映射更新数据库架构:
php app/console cache:clear