簡體   English   中英

如何過濾繼承的Doctrine個對象?

[英]How to filter inherited Doctrine objects?

每個Product都由給定Tenant (即用戶)“擁有”,並且需要一種顏色,該顏色可以是所有租戶可用的標准Color ,也可以是給定租戶創建且僅供該租戶使用的專有TenantOwnedColor

#[ORM\Entity]
class Product implements BelongsToTenantInterface
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private int $id;

    #[ORM\Column(type: 'string', length: 180)]
    private string $name;

    #[ORM\ManyToOne(targetEntity: Color::class)]
    #[ORM\JoinColumn(nullable: false)]
    private ?Color $color;

    #[ORM\ManyToOne(targetEntity: Tenant::class)]
    #[ORM\JoinColumn(nullable: false)]
    private ?Tenant $tenant;
}
#[ORM\Entity]
#[ORM\InheritanceType(value: 'JOINED')]
#[ORM\DiscriminatorColumn(name: 'type', type: 'string')]
#[ORM\DiscriminatorMap(value: ['open' => Color::class, 'proprietary' => TenantOwnedColor::class])]
class Color
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private int $id;

    #[ORM\Column(type: 'string', length: 180)]
    private string $name;

    #[ORM\Column(type: 'string', length: 255)]
    private string $colorCode;
}
#[ORM\Entity]
class TenantOwnedColor extends Color implements BelongsToTenantInterface
{
    #[ORM\ManyToOne(targetEntity: Tenant::class)]
    #[ORM\JoinColumn(nullable: false)]
    private ?Tenant $tenant;
}

為了過濾所有實現BelongsToTenantInterface的實體並將它們限制為登錄用戶所屬的Tenant ,偵聽器添加了一個 doctrine 過濾器。

namespace App\EventListener;

use Doctrine\ORM\EntityManager;
use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTAuthenticatedEvent;
use App\Entity\MultiTenenacy\BelongsToTenantInterface;

final class AuthenticatedTenantEntityListener
{
    public function __construct(private EntityManager $entityManager)
    {
    }

    public function onJWTAuthenticated(JWTAuthenticatedEvent $jwtAuthenticatedEvent): void
    {
        $user = $jwtAuthenticatedEvent->getToken()->getUser();
        if (!$user instanceof BelongsToTenantInterface) {
            return;
        }

        $this->entityManager
        ->getFilters()
        ->enable('tenant_filter')
        ->setParameter('tenantId', $user->getTenant()->getId());
    }
}
namespace App\Doctrine;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Query\Filter\SQLFilter;
use App\Entity\MultiTenenacy\BelongsToTenantInterface;

final class TenantFilter extends SQLFilter
{
    public function addFilterConstraint(ClassMetadata $classMetadata, $targetTableAlias): string
    {
        if ($classMetadata->getReflectionClass()->implementsInterface(BelongsToTenantInterface::class)) {
            return sprintf('%s.tenant_id = %s', $targetTableAlias, $this->getParameter('tenantId'));
        }        
        return '';
    }
}

我的方法適用於Product但不適用於TenantOwnedColor 在進行故障排除時,我發現TenantFilter::addFilterConstraint()正在傳遞未實現BelongsToTenantInterface的父 class (即Color )元數據,因此我現在知道它為什么不過濾。

我還在Doctrine 的文檔中發現了以下內容,很明顯這是設計使然:

在連接表或單表 inheritance 的情況下,您始終會獲得 inheritance 根的 ClassMetadata。 這是必要的,以避免在應用過濾器時會破壞 SQL 的邊緣情況。

為了克服這個缺點,還有其他方法可以實現嗎?

社區似乎已經多次提出這個話題。 似乎沒有正式的解決方法,由於那些著名的edge cases引起的 innestability,盡管有些人已經對問題進行了更改/破解/解決方法,因此這並非不可能

可能有幫助的鏈接,其中提到了一些解決方法,我希望你覺得它們足夠有用,很抱歉我不能提供更多幫助:

https://github.com/doctrine/orm/issues/7504#issuecomment-568569307

https://github.com/doctrine/orm/issues/6329

https://github.com/doctrine/orm/issues/6329#issuecomment-538854316

https://www.doctrine-project.org/projects/doctrine-orm/en/2.11/reference/php-mapping.html#classmetadata-api

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM