Symfony 3.4 - ManyToOne не может получить доступ к данным объекта

У меня есть объектный вызов Category, другой вызов Product и один посередине под названием CategoryProduct.

  • У меня есть отношение OneToMany между Category и CategoryProduct: @ORM\OneToMany(targetEntity = "CategoryProduct", mappedBy = "Catego", fetch = "EAGER") с инвертированнымBy в классе CategoryProduct (в $ catego).
  • У меня есть отношение OneToOne между CategoryProduct и Product: @ORM\OneToOne(targetEntity = "Product", inversedBy = "Category") с инверснымBy в классе Product (в категории $).

внутри моего CategoryController у меня есть такая функция:

public function getCategoryAction(Request $request)
{
    $category = $this->get('doctrine.orm.entity_manager')
                 ->getRepository('AppBundle:Category')
                 ->findAll();
    return new JsonResponse($category);
}

Возвращаемый результат дает коллекцию сущностей Category, но «суб-сущность» Product пуста. Когда я проверяю токен на предмет отладки в Symfony, я проверяю раздел Doctrine, и запрос работает отлично, данные загружаются, а в моем возвращении их просто нет. Я могу получить доступ к данным с помощью $category->getProduct() (он дает мне коллекцию ссылок продукта на категорию, как я хочу), но все же мой подкласс продукта пуст. Кто-нибудь знает почему?

Спасибо за вашу помощь.

Попробуйте запустить php bin/console doctrine:schema:validate --skip-sync и посмотрите, нет ли ошибок сопоставления. `

Carl Owens 30.11.2018 16:57

... или doctrine:shema:update

Paul 30.11.2018 17:12

Помимо полезного совета Карла по проверке схемы: вы уверены, что для каждого продукта может быть только один CategoryProduct? Зачем тогда вообще использовать «средний класс»? "InversedBy = " Category "" означает, что вам необходимо иметь свойство $ Category в классе вашего продукта. Но на самом деле это не категория, это CategoryProduct.

YetiCGN 01.12.2018 11:25

Я уже пробовал проверить / обновить схему, и там нет никаких проблем. Мне нужен класс в середине для некоторой информации, которую я не могу нигде сохранить, имя свойства не имеет значения, назовите его как хотите. В любом случае спасибо за вашу помощь

Alannn 10.12.2018 09:59
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
1
4
1 061
3

Ответы 3

Принимая решение с самого начала, ваша текущая проблема - это типичная вещь для Доктрины гидратации.

По умолчанию Doctrine лениво загружает отношения, это означает, что изначально Doctrine предоставляет прокси-коллекцию, которая не содержит в себе никаких элементов, и загружает фактические элементы только тогда, когда к ним каким-либо образом обращаются (например, при использовании геттера, такого как getProduct ()). Вот почему ваша коллекция товаров кажется пустой.

Вы можете легко изменить это, установив для атрибута fetch в вашей ассоциации значение EAGER:

// inside Category class
/**
 * @ManyToOne(targetEntity = "Product", fetch = "EAGER")
 */
 private $products;

Однако в конечном итоге ваш код не заработает, потому что, когда вы пытаетесь json_encode объект с частными свойствами, в результате вы получите только пустой json. Решение вашей проблемы - использовать собственный способ сериализации вашего объекта. Самое простое (и, вероятно) лучшее решение - использовать компонент Symfony Serializer. НО вы должны знать, что простое использование $serializer->serialize($category, 'json'); вызовет исключение циклической ссылки. Это будет вызвано тем, что (как я предполагаю) вы также имеете в своем классе продукта ссылку на категорию, подобную этой:

// inside Product class
/**
 * @OneToMany(targetEntity = "Category")
 */
private $category;

Как вы понимаете, Symfony попытается сериализовать категорию, в которой есть много продуктов, у которых есть категория, у которой есть много продуктов ... это круговая ссылка.

Чтобы обойти эту проблему, вы должны использовать такие группы сериализации:

// inside your controller, supposing you are using autowiring to inject services:

use Symfony\Component\Serializer\SerializerInterface;

public function getTariffsAction(Request $request, SerializerInterface $serializer)
{
    $category = $this->get('doctrine.orm.entity_manager')
             ->getRepository('AppBundle:Category')
             ->findAll();

    $categoryJson = $serializer->serialize($category, 'json', ['groups' => ['tariffs'] ]);

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

Затем явно настройте атрибуты ваших объектов, вы хотели бы попасть внутрь своих сущностей следующим образом:

// Category.php
use Symfony\Component\Serializer\Annotation\Groups;
...
/**
 * @ORM\Id
 * @Groups({"tariffs"})
 */
protected $id;

/**
 * @ORM\Column(type = "string")
 * @Groups({"tariffs"})
 */
protected $name;

/**
 * @ORM\ManyToOne(targetEntity = "Product")
 * @Groups({"tariffs"})
 */
private $product;

// any other attribute you want to include

И, наконец, в вашем Product.php:

Product.php

/**
 * @ORM\Id
 * @Groups({"tariffs"})
 */
protected $id;

/**
 * @ORM\Column(type = "string")
 * @Groups({"tariffs"})
 */
protected $productName;

// do not include the reference to the category to avoid circular reference
/**
 * @OneToMany(targetEntity = "Category")
 */
private $category;

Вы можете найти больше о компоненте сериализатора и группах сериализации в документация.

Извините за задержку, я пробовал метод, который вы мне дали, но ответ Json пуст, нет никакого свойства. Циркуляр кажется хорошей идеей, но один из моих коллег проверил и сказал, что здесь нет проблем ... В любом случае спасибо за вашу помощь. Если у вас есть другие идеи, я вас слышу! :)

Alannn 10.12.2018 10:01

Прежде всего вы должны выгрузить результат вашего запроса, чтобы увидеть, что вы действительно получаете, прежде чем сериализовать.

iiirxs 10.12.2018 10:20

Если вы попытаетесь json_encode для такого объекта, вы просто получите пустой json. Циклическая ссылка будет создана при попытке сериализации с использованием компонента сериализатора. Я обновлю свой ответ, чтобы прояснить это.

iiirxs 10.12.2018 10:26

Когда я попытался использовать var_dump, я увидел, что вы имели в виду, вы правы, есть круговая ссылка, но я не могу решить проблему с группами, я пробовал ...

Alannn 10.12.2018 12:38

в чем была твоя проблема?

iiirxs 10.12.2018 12:45

Ничего нового, отдача такая как у этого [{"id":1,"credits":0,"product":{},"statusId":2}]. Поле продукта должно быть массивом Json, который содержит таблицу продуктов моей базы данных.

Alannn 10.12.2018 14:01

вы, вероятно, неправильно установили атрибуты своей группы

iiirxs 10.12.2018 14:05

Кроме того, когда я попытался добавить строку @Groups({"tariffs"}) только к одному параметру, чтобы увидеть, дает ли она мне только эту строку, это не так ... Я скопировал / прошил строку, которую вы мне дали

Alannn 10.12.2018 14:07

1. правильно ли вы установили и использовали сериализатор Symfony? 2. вы добавили свойство аннотаций группы? например: (/ ** * @Groups ({"тарифы"}) * /) Если да, то каков результат $ serializer-> serialize (...)?

iiirxs 10.12.2018 14:15

извините, я забыл возврат. Я исправляю и получаю [[]]

Alannn 10.12.2018 14:23

разместите свою строку в контроллере, где вы используете сериализатор. также просто выгружайте результаты внутри контроллера и публикуйте то, что вы получаете, а не результат ответа json

iiirxs 10.12.2018 14:26

Ниже моего обновления контроллера с помощью метода, который вы мне дали.

public function getTariffsAction(Request $request, SerializerInterface $serializer) 
{
    $category = new Category();
    $category = $this->get('doctrine.orm.entity_manager')
            ->getRepository('AppBundle:Category')
            ->findAll();
    $categoryJson = $serializer->serialize($category , 'json', ['groups' => ['tariffs'] ]);
    return $this->json($categoryJson);
}

и когда я сбрасываю категорию $, я получаю то, что не могу вставить, потому что это слишком много. С Postman это делает мой компьютер очень глючным (один из моих экранов выключается), мне нужно перезагрузить после этого

Является ли $ categoryJson пустым строковым массивом? Вы как-то кешируете аннотации доктрины? Может быть, попытка очистить этот кеш поможет: php bin / console doctrine: cache: clear-metadata

iiirxs 12.12.2018 00:00

Проблема решена, вы были абсолютно правы, потому что это была круговая ссылка, и я решил ее с группами, как вы сказали. (Я использовал FOSRestBundle для групп проще, чем собственные методы symfony)

Другие вопросы по теме