@simonnik

Как в аннотациях Doctrine добавить статическое условие выборки?

Всем привет!

есть таблицы :
create table user
(
    id       int unsigned auto_increment
        primary key,
    username varchar(255) default '' not null,
    email    varchar(255) default '' not null,
    name     varchar(255) default '' not null
)
    charset = utf8mb3;

create table file_target
(
    id          int unsigned auto_increment
        primary key,
    file_id     int unsigned             null,
    file_type   int unsigned default '0' not null,
    target_id   int unsigned default '0' not null,
    target_type int unsigned default '0' not null
)
    charset = utf8mb3;

create table file
(
    id      int unsigned auto_increment
        primary key,
    user_id int unsigned            null,
    path    varchar(255) default '' not null
)
    charset = utf8mb3;


у таблицы file_target поля file_type - отвечает за класс сущности, например, за пользователя будет отвечать класс UserImage. target_type - отвечает за сущность, например, User. target_id - отвечает за идентификатор сущности, например, User::id.

Сущности:
/**
 * @ORM\Entity
 * @ORM\Table(name="user")
 */
class User
{
     /**
     * @var ArrayCollection|File[]
     * @ORM\ManyToMany(targetEntity="Core\Domain\File\Entity\File")
     * @ORM\JoinTable(
     *      name="file_target",
     *      joinColumns={
     *          @ORM\JoinColumn(name="target_id", referencedColumnName="id"),
     *      },
     *     inverseJoinColumns={
     *          @ORM\JoinColumn(name="file_id", referencedColumnName="id")
     *     }
     * )
     */
     private $file;
}

/**
 * @ORM\Entity
 * @ORM\Table(name="file_target")
 */
class FileTarget
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="integer", nullable=true)
     */
    private $file_id;

    /**
     * @ORM\Column(type="integer")
     */
    private $file_type;

    /**
     * @ORM\Column(type="integer")
     */
    private $target_id;

    /**
     * @ORM\Column(type="integer")
     */
    private $target_type;

    // ...
}

/**
 * @ORM\Entity
 * @ORM\Table(name="file")
 */
class File
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="integer", nullable=true)
     */
    private $user_id;

    /**
     * @ORM\Column(type="string")
     */
    private $path;

    // ...
}

Вопросы:
  1. Как для свойства $file сущности User сделать связь ManyToOne? Менял на нее, но получал ошибку "SQLSTATE[42S22]: Column not found: 1054 Unknown column 't0.file_id' in 'field list' " потому что из-за связи File, Doctrine генерит поле file_id. Работает только со связью ManyToMany
  2. Например, есть запрос SELECT * FROM users u
    LEFT JOIN file_target ft ON ft.target_id=u.id AND ft.target_type=5
    LEFT JOIN file f ON f.id=ft.file_id
    WHERE u.id=4
    Как добавить в аннотации статическое условие выборки target_type=5, типа @ORM\JoinColumn(name="target_type", columnDefinition="6") ?


Заранее благодарю
  • Вопрос задан
  • 106 просмотров
Решения вопроса 1
@tukreb
1. Чтобы разбить ManyToMany, на ManyToOneи OneToMany, вам нужно вручную выделить сущность FileTarget и вручную там расписать связи. Соответственно в сущности FileTarget
Вам нужно сделать что-то такое.
/**
 * @ORM\Entity
 * @ORM\Table(name="file_target")
 */
class FileTarget
{
    //другие свойства.
     /**
     * @ManyToOne(targetEntity="File" , inversedBy="fileTarget")
     * @JoinColumn(name="file_id", referencedColumnName="id")
     */
    private File|null $file= null;

}

В классе File создайте коллекцию OneToMany https://www.doctrine-project.org/projects/doctrine...

Далее тоже самое делаем ManyToOne в сущности File, но уже на User, а в самом User уже коллекцию OneToMany на File.
В итоге в сущности User вы сможете получить коллекцию на ваши file.
class User
{
    //другие свойства и функции.

    /** @return File[] */
    public function getFiles(): array {
        return $this->files->toArray();
    }
}


Далее через foreach достаём нужные объекты из getFiles() и обращаемся по свойствам объекта куда нужно.

2. Это делается через отельную функцию в сущности или лучше всего в сервисе.
Создаёте функцию в классе, где у вас есть доступ к User, по коду это получается класс File
public function getUserWithTargetType(int $targetType): User {
        //через foreach перебираете User и по условию $targetType возвращаете User 
    }

Хотя я бы это вынес в отдельный сервис скорее всего.

П.С Для меня странной выглядит ваша сущность FileTarget, у вас один файл может быть разных типов? Почему типы файлы не перенести в сущность файл? Как и всё остальное. Но в общем меня это волновать не должно :)
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
2. Через аннотации - никак. Если нужно работать только с помеченым файлом - добавляйте в сущность метод который выберет из коллекции нужный.
Если хотите избавится от оверфетчинга неиспользуемых файлов - запрашивайте сущность из репозитория, где уже прямо в запросе отфильтруйте ненужные.
Ответ написан
Комментировать
Ваш ответ на вопрос

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

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