Отображение нескольких объектов в одном поле - PullRequest
0 голосов
/ 02 марта 2020

Есть ли способ иметь одно поле в объекте, привязанном к нескольким различным объектам?

У меня есть объект «Задача», который может быть связан либо с объектом «Клиент», либо с объектом «Поставщик» (никогда оба). , В настоящее время оба поля разделены.

Мне нужно использовать это в форме TaskType, чтобы пользователи могли выбирать, с каким клиентом / поставщиком связывать задачу, в идеале под одним полем, так как я планирую добавить больше объектов, которые может ассоциироваться с.

/**
 * @ORM\ManyToOne(targetEntity="App\Entity\Customer", inversedBy="tasks")
 */
private $customer;
/**
 * @ORM\ManyToOne(targetEntity="App\Entity\Supplier", inversedBy="tasks")
 */
private $supplier;

public function getCustomer(): ?Customer
{
    return $this->customer;
}
public function setCustomer(?Customer $customer): self
{
    $this->customer = $customer;
    return $this;
}
public function getSupplier(): ?Supplier
...etc

1 Ответ

2 голосов
/ 02 марта 2020

Может быть, вы можете попробовать следующее:

В идеале, я думаю, вы хотите поделиться информацией между Customer и Supplier. Таким образом, мы могли бы ввести новый родительский класс, например, Person (я не знаю, какую ответственность они несут, поэтому мы возьмем наиболее "общее" имя класса c) и используем Doctrine отображение наследования :

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="discr", type="string")
 * @ORM\DiscriminatorMap({
 *  "customer" = "Customer",
 *  "supplier" = "Supplier"
 * })
 */
abstract class Person
{
  //... Fields, traits, embeddables...

  /**
   * A common attribute between our child classes
   * protected to respect encapsulation
   * 
   * @ORM\Column(type="text")
   */
  protected $name;

  /**
   * Here we define the general link to a task. It will be inherited by child classes
   *
   * @ORM\OneToMany(targetEntity="App\Entity\Task", mappedBy="assignedTo")
   */
  protected $tasks;

  // public getters/setters...
}

Я думаю, Стратегия наследования таблиц классов подойдет вам здесь, так как вы хотели бы добавить больше объектов позже. Таким образом, мы можем уважать принцип Открыто-закрыто и позже добавить больше дочерних классов вместо изменения логики c только в одном классе.

Также я сделал Person абстрактный класс, так как мы обычно хотим иметь дело с Customer или Supplier экземплярами. Но в зависимости от того, что вам нужно, может быть, вы можете удалить ключевое слово abstract. В этом случае вам нужно будет включить Person в карту дискриминатора.

Конечно, теперь Customer и Supplier должны оба расширять Person:

//...
class Customer extends Person
//...

//...
class Supplier extends Person
//...

Не забудьте удалить общие поля (например, id) из дочерних классов, теперь они будут унаследованы от Person

Итак, в Задаче , вы можете определить отношение ManyToOne к Person:

/**
 * @ORM\ManyToOne(targetEntity="App\Entity\Person", inversedBy="tasks")
 */
private $assignedTo;

Наконец, для вашей формы задачи, давайте составим список выбора с именами всех людей:

<?php

namespace App\Form;

use App\Entity\Person;
use App\Entity\Task;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class TaskType extends AbstractType
{
  public function buildForm(FormBuilderInterface $builder, array $options)
  {
    $builder
      // other task fields
      ->add('assignedTo', EntityType::class, [
        'class' => Person::class,
        'choice_label' => 'name',
      ]);
  }

  public function configureOptions(OptionsResolver $resolver)
  {
    $resolver->setDefaults([
      'data_class' => Task::class,
    ]);
  }
}

Он выберет всех людей, независимо от их типа. Затем вы можете расширить его позже с другими дочерними классами! Я надеюсь, что это поможет.

...