Невозможно включить коллекцию объектов внутри API ПОСЛЕ вызова

#php #api #symfony #doctrine-orm #fosrestbundle

#php #API #symfony #doctrine-orm #fosrestbundle

Вопрос:

Ошибка, о которой идет речь:

 Entity of type AppEntityNutt is missing an assigned ID for field  'squirrel'.
The identifier generation strategy for this entity requires the ID field to be populated before EntityManager#persist() is called.
If you want automatically generated identifiers instead you need to adjust the metadata mapping accordingly.
  

Я вполне могу вызвать api POST, чтобы добавить объект Squirrel в базу данных.
И, используя идентификатор этой Squirrel, я могу предварительно выполнить вызов POST для объекта Nutt, результатом которого будет правильно связанная запись в таблице Nutt.

Что я, похоже, не могу заставить работать, так это разрешить вызову Squirrel api включать соответствующую коллекцию Nutts, которую я хочу вставить в тот же вызов api.

Что я делаю не так?

Вызов JSON:

 {
    "name": "Jake",
    "nutts": [
        {
            "size": 10,
            "color": "blue"
        }
    ]
}
  

Entity Squirrel

 /**
 * @ORMEntity
 * @ORMTable(name="squirrel")
 */
class Squirrel {
  /**
   * @ORMColumn(type="integer")
   * @ORMId
   * @ORMGeneratedValue(strategy="AUTO")
   */
  private $id;
  /**
   * @ORMColumn(type="string", length=100)
   * @AssertNotBlank()
   *
   */
  private $name;
  /**
   * @ORMOneToMany(targetEntity="AppEntityNutt", mappedBy="squirrel", cascade={"persist", "remove"})
   */
  private $nutts;
  public function __construct()
  {
    $this->nutts = new DoctrineCommonCollectionsArrayCollection();
  }
  public function getId()
  {
    return $this->id;
  }
  public function setId($id)
  {
    $this->id = $id;
  }
  public function getName()
  {
    return $this->name;
  }
  public function setName($name)
  {
    $this->name = $name;
  }
  public function getNutts(): ?Collection
  {
    return $this->nutts;
  }
  public function setNutts(Collection $nutts)
  {
    foreach ($nutts as $nutt)
    {
      $this->nutts->add($nutt);
    }
  }
  public function addNutt(Nutt $nutt): Squirrel
  {
    $this->nutts->add($nutt);
    return $this;
  }
}
  

Обновлена Entity Squirrel.
setNutts был изменен на:

 public function setNutts(Collection $nutts)
{
  foreach ($nutts as $nutt)
  {
    $nutt->setSquirrel($this);
    $this->nutts->add($nutt);
  }
}
  

Объект Nutt

 /**
 * @ORMEntity
 * @ORMTable(name="nutt")
 */
class Nutt {
  /**
   * @ORMManyToOne(targetEntity="AppEntitySquirrel", inversedBy="nutts")
   * @ORMId
   */
  private $squirrel;
  /**
   * @ORMColumn(type="integer")
   * @ORMId
   */
  private $size;
  /**
   * @ORMColumn(type="text")
   * @AssertNotBlank()
   */
  private $color;
  /**
   * @return Squirrel|null
   */
  public function getSquirrel(): ?Squirrel
  {
    return $this->squirrel;
  }
  /**
   * @param Squirrel|null $squirrel
   * @return $this
   */
  public function setSquirrel(?Squirrel $squirrel): self
  {
    $this->squirrel = $squirrel;
    return $this;
  }
  //getters and setters for the rest
}
  

Entity Nutt has been updated.
Property $squirrel has its id notation removed as it is a relation:

 /**
 * @ORMManyToOne(targetEntity="AppEntitySquirrel", inversedBy="nutts")
 */
private $squirrel;
  

SquirrelController

 /**
 * Squirrel controller.
 * @Route("/api", name="api_")
 */
class SquirrelController extends AbstractFOSRestController
{
  /**
   * Lists all Squirrels.
   * @RestGet("/squirrels")
   * @return Response
   */
  public function getSquirrelAction()
  {
    $repository = $this->getDoctrine()->getRepository(Squirrel::class);
    $squirrels = $repository->findall();
    return $this->handleView($this->view($squirrels));
  }
  /**
   * Create Squirrel.
   * @RestPost("/squirrel")
   *
   * @return Response
   */
  public function postSquirrelAction(Request $request)
  {
    $squirrel = new Squirrel();
    $form = $this->createForm(SquirrelType::class, $squirrel);
    $data = json_decode($request->getContent(), true);
    $form->submit($data);
    if ($form->isSubmitted() amp;amp; $form->isValid()) {
      $em = $this->getDoctrine()->getManager();
      $em->persist($squirrel);
      $em->flush();
      return $this->handleView($this->view(['status' => 'ok'], Response::HTTP_CREATED));
    }
    return $this->handleView($this->view($form->getErrors()));
  }
}
  

И мой текущий фокус
Форма Squirrel

 class SquirrelType extends AbstractType
{
  public function buildForm(FormBuilderInterface $builder, array $options)
  {
    $builder
      ->add('name')
      ->add(
        'nutts',
        CollectionType::class, [
          'entry_type' => NuttType::class,
          'allow_add' => true,
          'by_reference' => false
        ])
      ->add('save', SubmitType::class);
  }
  public function configureOptions(OptionsResolver $resolver)
  {
    $resolver->setDefaults(array(
      'data_class' => Squirrel::class,
      'csrf_protection' => false
    ));
  }
}
  

Существует форма nutt, но она работает нормально.

Вопрос был решен @mel в комментарии

Комментарии:

1. @msg Спасибо, это очень помогло. Белка и Орех оба были добавлены, но теперь не связаны. У вас есть предложения и для этого? Если вы добавите предложение вместе со своим комментарием в отдельный ответ, я могу подписать вопрос.

2. @msg Я думаю, вам нужно только добавить свой комментарий в качестве ответа сейчас. Я обнаружил, что не добавлял squirrel в nutt в foreach для Squirrel::setNutts(). foreach ($nutts как $nutt){ $nutt->setSquirrel($this); $this-> nutts->add($nutt); }}

Ответ №1:

Id Аннотация объявляет столбец как первичный ключ, поэтому он становится обязательным. Но в данном случае это не требуется, поскольку squirrel это отношение.

Сама ошибка также указывает на то, что поле равно нулю при сохранении объекта, поэтому setSquirrel оно не вызывается.

Вы также можете удалить аннотацию из size .

Комментарии:

1. Что, если Nutt не может существовать без связи с белкой?

2. @vernes Вы можете контролировать, есть ли связь nullable или нет, с помощью аннотаций.