Сохранение новых сущностей в ассоциации «один ко многим», проиндексированной по полю, через конструктор форм Symfony - PullRequest
0 голосов
/ 21 февраля 2019

Мне потребовалось много времени, чтобы получить правильное название, и я еще не написал вопрос: /

Вот так: Мое меню загружено из сущностей.Чтобы пользователь мог перевести меню на несколько языков, я создал сущность Menu и сущность LocalizedMenu, связанную с Menu через ManyToOne связь.

После это краткое руководство , я проиндексировал связь с полем LocalizedMenu->locale.Это гарантирует, что в базе данных существует только один LocalizedMenu для каждой локали и эта доктрина перезаписывает существующие локали.

Вот как это выглядит:

/**
 * @ORM\Entity(repositoryClass="App\Repository\MenuRepository")
 */
class Menu
{
    /**
     * @Groups({"menu"})
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    // ...

    /**
     * References translated menus.
     * @Groups({"localized_menus"})
     *
     * @ORM\OneToMany(
     *     targetEntity="LocalizedMenu"
     *     ,mappedBy="parentMenu"
     *     ,indexBy="locale"
     *     ,cascade={"persist", "remove"}
     * )
     * @ORM\OrderBy({"locale" = "ASC"})
     */
    private $localizedMenus;

    // ...

    public function getLocalizedMenu($locale) {
        if (!isset($this->localizedMenus[$locale])) {
            return new LocalizedMenu($locale, $this);
        }
        return $this->localizedMenus[$locale];
    }

    public function addLocalizedMenu($localizedMenu): self
    {
        $this->localizedMenus[$localizedMenu->getLocale()] = $localizedMenu;

        return $this;
    }
}

LocalizedMenu - это сущность, которая содержитпереведенные пользователем поля меню:

/**
 * @ORM\Entity(repositoryClass="App\Repository\LocalizedMenuRepository")
 */
class LocalizedMenu
{
    public function __construct($locale, $menu) {
        $this->locale = $locale;
        $this->parentMenu = $menu;
        $this->parentMenu->addLocalizedMenu($this);
    }

    // region FIELDS
    /**
     * @Groups({"localized_menu", "localized_menus"})
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;
    /**
     * @Groups({"localized_menu", "localized_menus"})
     * @var $locale string
     * @ORM\Column(
     *     type                 = "string"
     *     ,unique              = true
     * )
     */
    private $locale = "";
    /**
     * @Groups({"localized_menu", "localized_menus"})
     * @ORM\Column(
     *     type                 = "string",
     *     length               = 75
     * )
     */
    private $title = "";
    /**
     * @Groups({"localized_menu", "localized_menus"})
     * @var $description string Extra description for this menu item
     * @ORM\Column(
     *     type                 = "text",
     *     name                 = "description"
     * )
     */
    private $description = "";
    /**
     * @Groups({"localized_menu", "localized_menus"})
     * @ORM\Column(
     *     type                 = "datetime",
     *     name                 = "creation_date"
     * )
     * @Assert\DateTime()
     */
    private $creationDate;
    /**
     * @Groups({"localized_menu", "localized_menus"})
     * @ORM\Column(
     *     type                 = "datetime",
     *     name                 = "edit_date"
     * )
     * @Assert\DateTime()
     */
    private $editDate;

    /**
     * @Groups({"localized_menu", "localized_menus"})
     * @ORM\Column(type="text")
     * @Assert\NotBlank(
     *     message = "Een menu item is een pagina die inhoud nodig heeft, vergeet dit niet"
     * )
     */
    private $content = "";

    /**
     * @var $parentMenu Menu Parent menu for this localized menu
     *
     * @Groups({"localized_menu", "localized_parent_menu"})
     * @ORM\ManyToOne(
     *     targetEntity="Menu",
     *     inversedBy="localizedMenus"
     * )
     */
    private $parentMenu;
}

Чтобы передать все это пользователю для редактирования, я создал форму MenyType:

    $builder
        ->add('localizedMenus', CollectionType::class, array(
            'entry_type' => LocalizedMenuType::class,
            "entry_options" => [
                "choice_locale" => $options["choice_locale"]
            ],
            'allow_add' => true,
            'allow_delete' => true,
            'required' => false
        ))

и форму LocalizedMenuType:

    $builder
        ->add('title', TextType::class, array(
            'label'             => 'Titel',
            'trim'              => true
        ))
        ->add('description', TextareaType::class, array(
            'label'             => 'Omschrijving',
            'trim'              => true
        ))
        ->add('content', TextareaType::class, array(
            'label'             => 'Inhoud',
            'trim'              => true,
            'attr'              => array('class' => 'tinymce'),
            'data'              => " "
        ))
        ->add('locale', LocaleType::class, array(
            "choice_translation_locale" => $options["choice_locale"]
        ))
    ;

Я "думаю", что эта логика верна, но после использования javascript для создания новых форм LocalizedMenu я получаю эту ошибку:

Слишком мало аргументов для функции App \ Entity\ LocalizedMenu :: __ construct (), 0 передано в /Users/robbievercammen/Projects/web/base/vendor/symfony/form/Extension/Core/Type/FormType.php в строке 136 и ожидается ровно 2

Как мне заставить мою форму корректно работать с моей логикой?

РЕДАКТИРОВАТЬ - РЕАЛЬНАЯ ПРОБЛЕМА

Сообщение об ошибке здесь не является настоящей ошибкой.Как я уже говорил, если я удаляю параметры конструктора, он сохраняет записи в базе данных.т.е. позволяя доктрине использовать ассоциацию для привязки новых записей LocalizedMenu к записи Menu.Вот как это выглядит в базе данных:

Menu

|id| //...
| 7| //...

LocalizedMenu

| id | locale | title   | description | creation_date       | edit_date           
| content | parent_menu_id |
----
|  4 | nl     | Contact | Contact     | 2019-02-21 14:02:47 | 2019-02-21 14:02:47 |
 Contact |           NULL |

проблема в том, что LocalizedMenu -> parent_menu_id имеет значение NULL.По какой-то причине мои настройки не генерируют идентификаторы для родительского меню.В следующий раз, когда меню извлекается из базы данных, $menu->getLocalizedMenus() возвращает пустой массив, потому что они не связаны должным образом.

Следуя упомянутой выше инструкции , это кажется единственным способомЯ могу сказать учение для индекса по $localizedMenu -> locale

1 Ответ

0 голосов
/ 21 февраля 2019

Вашему конструктору LocalizedMenu требуется два аргумента - $locale и $menu.Когда Symfony создает новый экземпляр LocalizedMenu для вновь представленных данных, он просто new LocalizedMenu() заполняет свои данные.

Если вам необходимо настроить способ создания объекта для нового / динамического содержимого вформы (например, когда у вас есть аргументы конструктора), вы должны установить опцию empty_data для вашего LocalizedMenuType класса.

См. https://symfony.com/doc/current/form/use_empty_data.html для получения дополнительной информации.

Oneиз ваших LocalizedMenu аргументов конструктора является экземпляром меню.Этот экземпляр меню нужно будет передать в LocalizedMenuType в качестве обязательного параметра.

class LocalizedMenuType extends AbstractType
{
    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setRequired('menu');
        $resolver->setAllowedTypes('menu', Menu::class);
        $resolver->setDefault('empty_data', function (Options $options) {
            return new LocalizedMenu($options['choice_locale'], $options['menu']);
        });
    }
}
...