Форма сборки с наследованием одной таблицы

#php #orm #doctrine-orm #symfony

#php #orm #доктрина-orm #symfony

Вопрос:

У меня есть моя статья о сущности и одно наследование одной таблицы, подобное этому :

 /**
 * Article
 *
 * @ORMTable(name="article")
 * @ORMEntity(repositoryClass="PMPlatformBundleRepositoryArticleRepository")
 * @ORMInheritanceType("SINGLE_TABLE")
 * @ORMDiscriminatorColumn(name="media", type="string")
 * @ORMDiscriminatorMap({"article" = "Article", "movie" = "Movie", "image" = "Image", "text" = "Text"})
 */
class Article
{
    protected $id;
    protected $title;
    protected $description;
    protected $author;
    //other attributes and setters getters
}

class Image extends Article
{
    private $path;
    //getter setter
}

 class Movie extends Article
{
    private $url;
    //getter setter
}
  

Итак, тип объекта моей статьи — это либо изображение, либо фильм, либо только текст. Хорошо, теперь я хотел бы создать форму, в которой пользователи могут публиковать новую статью: в этой форме пользователь должен выбирать между типом дерева (3 кнопки переключения): изображение ИЛИ фильм ИЛИ только текст и, конечно, другие поля: заголовок и описание. Как я могу это сделать? Потому что с помощью команды

доктрина php bin / console:сгенерировать: сформировать MyBundle:Статья

Отображаемая форма :

 class ArticleType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('title',          TextType::class)
            ->add('description',    TextareaType::class)
            ->add('save',           SubmitType::class);
        ;
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'PMPlatformBundleEntityArticle'
        ));
    }
}
  

Я не знаю, как реализовать мое отношение STI в этой форме. Потому что у меня нет поля в моей статье entity / object для типа (только в моей таблице).
Я должен добавить пользовательское поле ChoiceType(), но для этого требуется атрибут.
Когда я пытаюсь добавить это в форму :

         ->add('path',           SearchType::class)
        ->add('url',            UrlType::class)
  

Я получил эту ошибку :

Ни свойство «path», ни один из методов «getPath ()», «path ()», «isPath ()», «hasPath ()», «__get ()» не существуют и не имеют общедоступного доступа в классе «PM PlatformBundle Entity Article».

Потому что я создал экземпляр статьи, а не экземпляр изображения или фильма. Изначально я создал STI, думая, что новый экземпляр Article позволит мне также определить «тип» article . Но нет? Верно?

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

1. Добавьте mapped:false опцию для полей формы, которые не должны быть сопоставлены с атрибутом базового объекта (Article). Затем вам нужно будет найти способ правильно обработать эту форму самостоятельно.

2. Хм, я не знаю, стоит ли использовать mapped:false . Что я должен сделать, чтобы правильно восстановить путь и URL, потому что они действительно существуют в моей базе данных и в моем объекте (но через наследование)?

3. Но у вас там нет Image / Movie object , не так ли? Нет, вы этого не делаете. Итак, как это должно работать, по вашему мнению (неважно, возможно это или нет)?

4. Да, у меня есть, посмотрите мой первый пост выше! У меня есть один фильм класса и одно изображение (расширяет статью).

5. У вас есть класс , а не экземпляр объекта , переданный форме.

Ответ №1:

Вам нужно будет создать три формы (одну для an Article , одну для a Movie и одну для an Image ). Затем в вашем контроллере у вас есть опции для работы с ними:

  • Либо вы используете одно действие для обработки трех форм (вы можете проверить, какая из них отправлена с помощью $form->isSubmitted() )
  • Вы создаете одно действие по форме и устанавливаете URL действия формы для каждой формы на правильный контроллер.

Наконец, в вашем шаблоне вы инкапсулируете свои формы в div и используете пример из моего предыдущего поста.

 {% extends "CoreBundle::layout.html.twig" %}

{% block title %}{{ parent() }}{% endblock %}

{% block btn_scrollspy %}
{% endblock %}


{% block bundle_body %}
    <div class="well">
        <div class="selector">
            <input type="radio" name="form-selector" value="article-form"> Article
            <input type="radio" name="form-selector" value="movie-form"> Movie
            <input type="radio" name="form-selector" value="image-form"> Image
        </div>

        <div class="form article-form" style="display: none;">
            {{ form(articleForm) }}
        </div>
        <div class="form movie-form" style="display: none;">
            {{ form(movieForm) }}
        </div>
        <div class="form image-form" style="display: none;">
            {{ form(imageForm) }}
        </div>
    </div>
{% endblock %}
  

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

1. Можете ли вы более точно объяснить мне, как сделать «одно действие по форме и установить URL-адрес действия формы для каждой формы для правильного контроллера».? Потому что я создал 3 формы, как вы говорите, и использовал опцию bootstrap Toggelable для просмотра (замените свой JS-код на скрыть / показать правильную форму). Это отлично работает, но я не могу создать систему: одно действие по форме, потому что изначально у меня есть один маршрут для одного контроллера для одного представления, и теперь у меня есть 3 действия для 3 маршрута для ОДНОГО представления.

2. В ссылке в моем ответе объясняется, как определить действие (=> URL, которое будет вызываться при отправке формы) для вашей формы. Итак, в ваших формах вам просто нужно установить маршрут, соответствующий нужному контроллеру.

Ответ №2:

Я согласен с dragoste в комментариях: вы не можете ожидать, что форма сама определит тип класса, который вы хотите создать, на основе значения.

Грубо говоря, Image и Movie имеют тот же тип, Article что и , но an Article не является Image and / или a Movie .

Вам нужно будет проверить это вручную. Вы можете сделать это на стороне сервера, как описано в комментариях, с полем, используемым mapped: false для определения типа объекта, который вам нужно создать, или на стороне клиента с помощью javascript, используя три формы (одна для фильма, одна для статьи, одна для изображения) и отображая правильную форму на основеваш переключатель.


Редактировать: Как отобразить правильную форму в JS?

Я создал JSFiddle, чтобы показать вам, как вы можете сделать это с помощью jQuery: https://jsfiddle.net/61gc6v16 /

С документацией jQuery вы сможете быстро понять, что делает этот образец, и адаптировать его к вашим потребностям. 🙂

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

1. Хорошо, спасибо за ваше объяснение! Я хотел бы создать эту систему форм с использованием javascript. Но у меня нет знаний о JS или Jquery для этого. Для этого требуется много JS-кода?

2. Я отредактировал свой ответ. 🙂 JavaScript — это хороший способ улучшить работу ваших пользователей и, в то же время, он может предотвратить некоторые головные боли от того, как обращаться с вещами на стороне сервера. Вы должны взглянуть на нее, так как сейчас она практически незаменима для веб-разработчиков, как на заднем, так и на переднем плане. jQuery — хорошее начало для понимания логики языка, поскольку он довольно прост в освоении и обладает отличными функциональными возможностями. Тем не менее, имейте в виду, что знание jQuery не означает знание JavaScript, и что существует гораздо больше фреймворков, которые могут предоставить вам гораздо больше замечательных вещей. 🙂

Ответ №3:

@Boulzy Я сделал это, и это работает:

     class ArticleController extends Controller
    {
        public function addAction(Request $request)
        {
            $form1 = $this->get('form.factory')->create(TextOnlyType::class);
            $form2 = $this->get('form.factory')->create(ImageType::class);
            $form3 = $this->get('form.factory')->create(MovieType::class);
            return $this->render('PMPlatformBundle:Article:add.html.twig', array(
                'ArticleTextform' => $form1->createView(),
                'ArticleImageform' => $form2->createView(),
                'ArticleMovieform' => $form3->createView(),
            ));
        }

        public function addArticleTextAction(Request $request)
        {
            $ArticleText = new TextOnly;
            $form = $this->get('form.factory')->create(TextOnlyType::class, $ArticleText);
            if ($request->isMethod('POST') amp;amp; $form->handleRequest($request)->isValid()) {
                $ArticleText->setAuthor(5);
                $ArticleText->setLikes(0);
                $em = $this->getDoctrine()->getManager();
                $em->persist($ArticleText);
                $em->flush();

                $request->getSession()->getFlashBag()->add('notice', 'Annonce bien enregistrée.');

                $listComments = $ArticleText->getComments();
                return $this->render('PMPlatformBundle:Article:view.html.twig', array(
                    'article' => $ArticleText,
                    'listComments' => $listComments
                ));
            }
            return $this->render('PMPlatformBundle:Article:add.html.twig', array(
                'form' => $form->createView(),
            ));
        }

        public function addArticleImageAction(Request $request)
        {
           //the same system as TextOnly
        }

        public function addArticleMovieAction(Request $request)
        {
           //the same system as TextOnly
        }
}
  

(Я переопределяю действие непосредственно в моем шаблоне. С помощью метода POST.)
addAction — это мой компонент, который вызывается по маршруту для отображения представления трех форм. Как вы можете видеть, этот код работает до тех пор, пока в отправленной форме нет ошибок. Потому что в этом случае (при возникновении ошибки при отправке формы) каждый контроллер должен возвращать начальное представление с 3 формами. Как я могу это сделать?

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

1. Взгляните на эти документы, выберите тот, который кажется вам наиболее интересным: symfony.com/doc/current/controller/forwarding.html , symfony.com/doc/current/controller.html#redirecting . Я рад, что могу помочь, но вы же знаете, что я не собираюсь кодировать весь ваш сайт, верно? Я имею в виду, что попытки, неудачи, повторные попытки, ошибки и упорство являются неотъемлемой частью процесса обучения. Вы должны попробовать больше решений, провести дополнительные исследования, прежде чем обращаться сюда за помощью. Таким образом, вы будете учиться лучше и быстрее.