Symfony 3中如何在SQLFilter内获取当前登录用户的企业信息
解决Symfony多租户过滤器中获取用户企业信息的问题
我懂你现在的困扰——刚上手Symfony搭建多租户应用,想让关联企业表的数据自动按当前登录用户所属企业过滤,但Doctrine过滤器里死活拿不到用户的企业信息对吧?别着急,咱们一步步把这个问题搞定:
1. 先确保自定义User类的企业关联没问题
首先得把基础打牢,你的自定义User实体得正确关联企业,并且有能拿到企业ID的方法,比如:
// src/AppBundle/Entity/User.php namespace AppBundle\Entity; use FOS\UserBundle\Model\User as BaseUser; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity * @ORM\Table(name="fos_user") */ class User extends BaseUser { /** * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Company") * @ORM\JoinColumn(nullable=false) */ private $company; // ... 其他字段和自动生成的方法 public function getCompany() { return $this->company; } public function getCompanyId() { return $this->company ? $this->company->getId() : null; } }
这一步很关键,确保你能从用户对象里顺利拿到企业ID。
2. 把Doctrine过滤器改成Symfony服务
默认的Doctrine过滤器不是Symfony服务,没法直接注入Security组件来拿用户信息。咱们得把过滤器注册成服务,这样就能注入TokenStorageInterface获取当前登录用户了。
先修改你的过滤器类,让它接受TokenStorageInterface的注入:
// src/AppBundle/Doctrine/Filter/CompanyFilter.php namespace AppBundle\Doctrine\Filter; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Query\Filter\SQLFilter; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; class CompanyFilter extends SQLFilter { private $tokenStorage; public function __construct(TokenStorageInterface $tokenStorage) { $this->tokenStorage = $tokenStorage; } public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias) { // 跳过不需要过滤的实体(比如User实体本身,或者没关联企业的模型) if (!$targetEntity->hasAssociation('company')) { return ''; } $user = $this->tokenStorage->getToken()?->getUser(); // 一定要判断用户是否已登录、是否是合法对象,避免匿名访问或异常情况报错 if (!$user || !is_object($user) || !method_exists($user, 'getCompanyId')) { return ''; } $companyId = $user->getCompanyId(); if (!$companyId) { return ''; } // 生成过滤SQL,这里假设实体关联企业的字段是company_id return sprintf('%s.company_id = %d', $targetTableAlias, $companyId); } }
然后在services.yml(或者config.yml的services区块)里把这个过滤器注册成服务:
# app/config/services.yml services: app.doctrine.company_filter: class: AppBundle\Doctrine\Filter\CompanyFilter arguments: ['@security.token_storage'] tags: - { name: doctrine.orm.sql_filter, filter_name: company_filter }
3. 在Doctrine配置里启用过滤器
回到你的config.yml的Doctrine部分,启用咱们刚配置的过滤器:
# app/config/config.yml doctrine: dbal: # 你的数据库连接配置... orm: # 其他ORM配置(比如实体路径、代理类设置等)... filters: company_filter: class: AppBundle\Doctrine\Filter\CompanyFilter enabled: true
因为咱们已经把过滤器注册成服务了,Doctrine会自动用服务实例,依赖的TokenStorageInterface也会被正确注入,不用再担心拿不到用户信息啦。
4. 几个要注意的细节
- 匿名用户场景:一定要在过滤器里判断用户是否登录,不然匿名访问时会直接报错。
- 实体范围控制:如果不是所有实体都需要过滤,可以自定义注解来标记需要过滤的实体,这样过滤器只会给标记过的实体加条件,更灵活。
- 命令行环境:如果在命令行执行脚本(比如数据迁移、批量导入),此时没有登录用户,过滤器会返回空条件,不会过滤数据。如果需要命令行也指定企业,可以额外加逻辑,比如通过命令参数传递企业ID。
这样配置完之后,你查询关联企业的实体时,Doctrine会自动在SQL里加上企业ID的过滤条件,不用每次查询都手动写where子句了!
内容的提问来源于stack exchange,提问作者KariBou
相关产品推荐
相关产品推荐

