Задать вопрос
@enigma2030

Symfony OneToMany Fetch: Eager with ULID primary key?

Добрый день.

Подскажите как исправить.

Есть 2 сущности
Product

<?php
namespace App\Entity;

use Symfony\Component\Uid\Ulid;
use Symfony\Bridge\Doctrine\Types\UlidType;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\{ ArrayCollection, Collection };

use App\Repository\ProductRepository;

#[ORM\Entity(repositoryClass: ProductRepository::class)]
#[ORM\Table(name: 'product')]
class Product
{
    #[ORM\Id]
    #[ORM\Column(type: UlidType::NAME, unique: true)]
    #[ORM\GeneratedValue(strategy: 'CUSTOM')]
    #[ORM\CustomIdGenerator(class: 'doctrine.ulid_generator')]
    private ?Ulid $id = null;

    #[ORM\Column]
    private ?string $name = null;

    #[ORM\OneToMany(targetEntity: Image::class, mappedBy: 'product', cascade: [ 'persist', 'remove' ], fetch: 'EAGER')]
    #[ORM\JoinColumn(name: 'product_id', referencedColumnName: 'id')]
    private Collection $images;

    public function __construct()
    {
        $this->images = new ArrayCollection();
    }

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

    public function getUlid(): ?string
    {
        return $this->id->toRfc4122();
    }

    public function getName(): ?string
    {
        return $this->name;
    }

    public function setName(?string $name): static
    {
        $this->name = $name;

        return $this;
    }

    public function getImages(): Collection
    {
        return $this->images;
    }
}


Image

<?php
namespace App\Entity;

use Symfony\Component\Uid\Ulid;
use Symfony\Bridge\Doctrine\Types\UlidType;

use Doctrine\ORM\Mapping as ORM;

use App\Entity\Product;
use App\Repository\ImageRepository;

#[ORM\Entity(repositoryClass: ImageRepository::class)]
#[ORM\Table(name: 'image')]
class Image
{
    #[ORM\Id]
    #[ORM\Column(type: UlidType::NAME, unique: true)]
    #[ORM\GeneratedValue(strategy: 'CUSTOM')]
    #[ORM\CustomIdGenerator(class: 'doctrine.ulid_generator')]
    private ?Ulid $id = null;

    #[ORM\ManyToOne(targetEntity: Product::class, inversedBy: 'images')]
    private ?Product $product = null;
    
    public function getId(): ?Ulid
    {
        return $this->id;
    }

    public function getUlid(): ?string
    {
        return $this->id->toRfc4122();
    }

    public function getProduct(): ?Product
    {
        return $this->product;
    }

    public function setProduct(?Product $product): static
    {
        $this->product = $product;

        return $this;
    }
}



Стандартная выборка из репозитория
ProductController

<?php
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\{ Request, Response };
use Symfony\Component\Routing\Annotation\Route;

use App\Repository\ProductRepository;

class ProductController extends AbstractController
{
    #[Route('/products', name: 'products')]
    public function index(ProductRepository $productRepository): Response
    {
        $output = [ 'data' => [], 'included' => [] ];

    	$productCollection = $productRepository->findAll();

    	foreach ($productCollection as $entity) {
    		$item = [
    			'id' => $entity->getUlid(),
    			'attributes' => [
    				'name' => $entity->getName()
    			]
    		];

    		$images = $entity->getImages();

    		foreach ($images as $image) {
    			$output['included']['images'][] = [
    				'id' => $image->getUlid(),
    				'relationships' => [
    					'product' => $entity->getUlid()
    				]
    			];
    		}

    		$output['data'][] = $item;
    	}

        return $this->json($output);
    }
}



При использовании Symfony\Component\Uid\Ulid вместо первичного ключа результат выборки следующий

65f429f5599d6016622700.png

При этом $images пустой

Если же просто изменить первичный ключ на

#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;


То все работает как надо, запрос тот же самый, но вместо Symfony\Component\Uid\Ulid в параметрах там INT, но при этом $image полноценная коллекция из которой можно получить все данные.

Composer
require

"require": {
        "php": ">=8.2",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "doctrine/dbal": "^3",
        "doctrine/doctrine-bundle": "^2.11",
        "doctrine/doctrine-migrations-bundle": "^3.3",
        "doctrine/orm": "^3.1",
        "symfony/console": "7.0.*",
        "symfony/dotenv": "7.0.*",
        "symfony/flex": "^2",
        "symfony/framework-bundle": "7.0.*",
        "symfony/runtime": "7.0.*",
        "symfony/uid": "7.0.*",
        "symfony/yaml": "7.0.*"
    }

  • Вопрос задан
  • 133 просмотра
Подписаться 1 Простой Комментировать
Пригласить эксперта
Ответы на вопрос 1
Стоило бы посмотреть как sql запрос в итоге формируется и где происходит несоответствие форматов.

При передаче в качестве параметра запроса можно явно сконвертировать Ulid в нужный формат:
$entity->getUlid()->toBase32()
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы