#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 . Я рад, что могу помочь, но вы же знаете, что я не собираюсь кодировать весь ваш сайт, верно? Я имею в виду, что попытки, неудачи, повторные попытки, ошибки и упорство являются неотъемлемой частью процесса обучения. Вы должны попробовать больше решений, провести дополнительные исследования, прежде чем обращаться сюда за помощью. Таким образом, вы будете учиться лучше и быстрее.