【问题标题】:FOSUserBundle Override Roles - Property "roles" in "Acme\DemoBundle\Entity\User" was already declared, but it must be declared only onceFOSUserBundle 覆盖角色 - “Acme\DemoBundle\Entity\User”中的属性“roles”已声明,但只能声明一次
【发布时间】:2014-05-08 06:10:11
【问题描述】:

我喜欢大多数人都在尝试覆盖 FOSUserBundle 角色,这样我就可以将它们 ManyToMany 映射到角色实体。

不幸的是,由于模型/用户的映射,我得到以下信息:

Property "roles" in "Acme\DemoBundle\Entity\User" was already declared, but it must be declared only once

在 FOSUserBundle 中发布的这个 git 问题中似乎提到了一些解决方法:

https://github.com/FriendsOfSymfony/FOSUserBundle/pull/1081#issuecomment-19027818

我是 Doctrine ORM,使用注解进行映射,而不是 yml 或 xml。最新的 Symfony (2.4) 和最新的 FOSUB。

我尝试了替代选项,将所有内容复制到我的实体中而不是扩展,但老实说,这搞砸了一切。

我正在尝试创建我自己的模型/用户扩展 FOSUserBundle/模型/用户而没有映射的想法。然后从这里扩展我的实体/用户。我试过了,但我仍然遇到同样的问题。我假设我做错了。

有人可以建议/展示我如何正确地做到这一点吗?

我确实需要能够覆盖角色,因为虽然 FOSUserBundle 很棒,但角色的适应不是很好。尽管当时我很感激这是他们可以做到的唯一方法,但现在更改它会破坏 BC。

希望有人能提供帮助。

亲切的问候 保罗·庞德

【问题讨论】:

  • 为什么不使用 FOSUserBundle 的群组功能?
  • 不要使用 FOS 提供的用户包。这将是一个地狱般的旅程。更好地构建您的自定义 user provider。很容易实现。
  • 我已经在我的应用程序中使用 Groups 来将用户存储在公司中并针对他们应用角色。我仍然需要能够对特定用户应用角色,而不是对它们进行分组。 @cept0 - 我同意,但它非常适合我需要它(除了角色):)
  • 可能是我最终使用了 Groups,并改变了我存储公司的方式,但我想我会先调查一下。另外,FOSUserBundle 与我正在使用的其他捆绑包集成得很好,所以现在不想破坏该链接。
  • @PaulPounder 关于您对 FOS 用户包的完整性的评论:没有特殊的魔法 FOS 用户包 集成。捆绑包将自己集成到到 Symfony 中,其他捆绑包可能会使用这个“桥梁”。

标签: php symfony doctrine-orm fosuserbundle symfony-2.4


【解决方案1】:

我也遇到了同样的问题,也使用了注解。

注意:由于一些读者无法将所有内容放在一起,我创建了一个gitHub repo with my UserBundle。如果您发现此 HowTo 中缺少某些内容,请告诉我,以便我添加。

这篇文章涵盖三个方面,基于 DB 的角色与树结构实现,框架配置也支持 DB 角色的 RoleHierarchy (getReachableRoles)。没有它,毕竟在 DB 中扮演角色是没有用的。和 Doctrine Subscribers 在某些实体被持久化时创建角色。

FOS 必须做出的改变是深刻的,并且有据可查,但我必须说,单个 HowTo Use 示例代码会阻止我阅读很多内容,(不要抱怨,至少我对编译器通行证有一点了解现在。)

数据库角色

我使用的是 Sf 2.4,但这应该从 2.3 开始工作。这是我的解决方案涉及的文件,每个文件考虑一个步骤:

./:
composer.json

src/Application/UsuarioBundle/:
ApplicationUsuarioBundle.php

src/Application/UsuarioBundle/Resources/config/doctrine/model/:
User.orm.xml

src/Application/UsuarioBundle/Entity/:
Role.php  Usuario.php

在copmoser.json 中,我升级了学说包,因此它包含了所需的文件:

"require": {
...
    "doctrine/doctrine-bundle": "~1.3@dev",
...
}

在Bundle.php 文件中,您必须注册编译器通道

namespace Application\UsuarioBundle;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\DoctrineOrmMappingsPass;

class ApplicationUsuarioBundle extends Bundle
{

    public function build(ContainerBuilder $container)
    {
        parent::build($container);
        $mappings = array(
            realpath(__DIR__ . '/Resources/config/doctrine/model') => 'FOS\UserBundle\Model',
            realpath(__DIR__ . '/Resources/config/doctrine/model') => 'FOS\UserBundle\Entity', 
        );

        $container->addCompilerPass(
            DoctrineOrmMappingsPass::createXmlMappingDriver(
                $mappings, array('fos_user.model_manager_name'), false
            )
        );
}

这是新版doctrine-bundle导入的依赖:

`\Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\DoctrineOrmMappingsPass`. 

我假设这个映射信息是在 FOSUSerBundle 之后添加的,因为我只是重复了我在 FOSUerBundle.php 中看到的过程(仅针对 ORM 进行了简化),希望它优先并且确实如此。

User.orm.xml 中的映射是 ./vendor/friendsofsymfony/user-bundle/FOS/UserBundle/Resources/config/doctrine/model/User.orm.xml 的精确副本,第 35 行已被注释掉。 这将删除映射超类中角色的冲突映射。

<!--<field name="roles" column="roles" type="array" />-->

从现在开始,您只需要首先做您想做的事,实现您对角色的想法。 这是我的: 扩展 FOS\UserBundle\Model\User 的用户类,但现在使用您在包中使用的映射。

src/Application/UsuarioBundle/Entity/Role.php

还有角色类:

src/Application/UsuarioBundle/Entity/Usuario.php

执行此操作后,您可以看到正确的 SQL 更改已通过 schema update --dump-sql 转储。

$ php app/console doctrine:schema:update --dump-sql --complete
CREATE TABLE fos_usuario_role (usuario_id INT NOT NULL, role_id INT NOT NULL, INDEX IDX_6DEF6B87DB38439E (usuario_id), INDEX IDX_6DEF6B87D60322AC (role_id), PRIMARY KEY(usuario_id, role_id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
CREATE TABLE fos_role (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(30) NOT NULL, role VARCHAR(20) NOT NULL, UNIQUE INDEX UNIQ_4F80385A57698A6A (role), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
ALTER TABLE fos_usuario_role ADD CONSTRAINT FK_6DEF6B87DB38439E FOREIGN KEY (usuario_id) REFERENCES fos_user (id) ON DELETE CASCADE;
ALTER TABLE fos_usuario_role ADD CONSTRAINT FK_6DEF6B87D60322AC FOREIGN KEY (role_id) REFERENCES fos_role (id) ON DELETE CASCADE;
ALTER TABLE fos_user DROP roles;

不过,我并不代表我需要的角色层次结构。

希望它对某人有用。我确定你已经解决了这个问题,或者失去了工作:p。

我遵循的文档:

https://github.com/symfony/symfony/pull/7599
https://github.com/FriendsOfSymfony/FOSUserBundle/pull/1081
http://symfony.com/doc/2.4/cookbook/doctrine/mapping_model_classes.html
http://symfony.com/doc/current/cookbook/service_container/compiler_passes.html

角色层次实现

解决方案中涉及的文件:

// The Magician, for I just re-instantiated RoleHierarchyVoter & ExpressionVoter 
// classes as ApplicationUsuarioBundle services; passing my RoleHierarchy 
// implementation. 
src/Application/UsuarioBundle/Role/RoleHierarchy.php

// duplicating security.access.expression_voter && 
// application_usuario.access.role_hierarchy_voter BUT WITH NEW 
// RoleHierarchy ARGUMENT
src/Application/UsuarioBundle/Resources/config/services.xml

// Entities, important methods are collection related
src/Application/UsuarioBundle/Entity/Role.php
src/Application/UsuarioBundle/Entity/Usuario.php

// Edited, commented out regular hardcoded roleHierarchy
app/config/security.yml

// CRUD related, sample files will add dependencies to lexik/form-filter-bundle; 
// docdigital/filter-type-guesser; white-october/pagerfanta-bundle
src/Application/UsuarioBundle/Controller/RoleController.php
src/Application/UsuarioBundle/Form/RoleType.php
src/Application/UsuarioBundle/Resources/views/Role/edit.html.twig
src/Application/UsuarioBundle/Resources/views/Role/index.html.twig
src/Application/UsuarioBundle/Resources/views/Role/new.html.twig
src/Application/UsuarioBundle/Resources/views/Role/show.html.twig

你可以在this gist看到文件

或者直接访问每个文件,(因为 Gist 不保留列表顺序)。

src/Application/UsuarioBundle/Role/RoleHierarchy.php

src/Application/UsuarioBundle/Resources/config/services.xml

src/Application/UsuarioBundle/Entity/Role.php

src/Application/UsuarioBundle/Entity/Usuario.php

app/config/security.yml

src/Application/UsuarioBundle/Controller/RoleController.php

src/Application/UsuarioBundle/Form/RoleType.php

src/Application/UsuarioBundle/Resources/views/Role/edit.html.twig

文档如下:

cookbook: security voters

Components: Security

reference: Service tags priorities

Souce: RoleHierarchyInterface

教义订阅者

你会走到这一步才能意识到缺少一些东西......

我将 Roles 移植到 DB 的主要原因是因为我正在处理一个动态的(从结构的角度来看)应用程序,它使用户能够配置工作流。当我添加一个新区域、一个新流程、一个新活动(或更新名称或父子关系,或删除任何)时,我需要生成新角色automatically。

然后您会想到 LyfeCycleEvents 的 Doctrine 订阅者,但在 PrePersist/PreUpdate 中添加新实体将需要嵌套刷新,在我的情况下这会搞砸,当您只需要更新已经“computedChanges”上的某些字段时会更容易“实体。

所以我用来挂钩和创建/编辑/删除角色的是 onFlush,此时 computChangeSet() 可以很好地添加新实体..

我将以ProcessRolesSubscriber Gist 为例。

【讨论】:

  • 感谢您对 StackOverflow 编辑器的坚持。这是一个很好的解决方案。老实说,我还没有解决它,谢天谢地,我还在工作:-)
  • 谢谢,很高兴你还在工作:)。我正在为此实施 RoleHierarchyVoter。完成后我会将其添加到答案中。
  • 谢谢,非常有帮助的帖子。但有一个问题。当您想从 User 中完全删除 $roles 时,例如,如果您将其存储在单独的数据库中,因为 EntityManager 从所有父类加载元数据,因此结果它将失败,但没有这样的列“roles”。
  • 谢谢。您必须实现用户提供者接口,只需确保实现getRoles() 方法并从用户中删除角色字段。然后更新您的架构。抱歉,我无法查阅我的代码。我正在通过手机发帖。
  • 我遵循了确切的步骤,但得到了这个异常 [Doctrine\ORM\Mapping\MappingException] "St\UserBundle\Entity\User" 中的属性 "roles" 已经声明,但只能声明一次
猜你喜欢
  • 2015-04-09
  • 1970-01-01
  • 2016-08-27
  • 1970-01-01
  • 2014-08-19
  • 1970-01-01
  • 2021-02-26
  • 2018-02-10
  • 2014-12-10
相关资源
最近更新 更多