【问题标题】:Combining 2 forms in symfony在symfony中结合2种形式
【发布时间】:2016-12-29 17:50:59
【问题描述】:

我有一个实体书,其中包含:

/**
 * @var \Doctrine\Common\Collections\ArrayCollection
 * @ORM\OneToMany(targetEntity="Reviewr\ReviewsBundle\Entity\Review", mappedBy="bookID")
 */
protected $reviews;

在 Review 实体中,我有要表示的字段:

userID
bookID
posted
comment

在我的 BookType 中,我正在尝试创建还包括 ReviewType 表单中的字段的表单:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('author')
        ->add('title')
        ->add('summary')
        ->add('reviews', ReviewType::class)
        ->add('submit', SubmitType::class);
}

但是,我似乎无法正常工作。我只是想拥有一个使用书籍实体和评论实体中的字段的表单。

我收到此错误:

The form's view data is expected to be an instance of class Reviewr\ReviewsBundle\Entity\Review, but is an instance of class Doctrine\Common\Collections\ArrayCollection.

有谁知道我做错了什么?

更新 使用当前的答案,它最终会显示一些内容.. 只是一个字符串“Reviews”,而不是 ReviewType 表单中的字段(userID、bookID、posted 和 comment),如下图所示:

为什么不显示字段?

【问题讨论】:

  • 您是否尝试在 ReviewType 中使用 EntityType?
  • @DanCostinel 我已经更新了问题,以便您更好地了解正在发生的事情
  • 我猜你的{{ form_end(form) }} 会显示“评论”字符串。看看你是否正确渲染了相应的字段。
  • @DanCostinel 不,我只是使用 form_end(form).. 我应该如何渲染它,因为 form_widget(form.reviews.userID) 也不起作用
  • 创建一个{{ dump(form) }} 并查看该字段的后代。

标签: php forms symfony


【解决方案1】:

由于您的图书有许多评论(不是一个),因此您必须将评论映射为一个集合类型,其中的每个条目都将是 Review 类型

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('author')
        ->add('title')
        ->add('summary')
        ->add('reviews', CollectionType::class, array(
            'entry_type' => ReviewType::class
        ))
        ->add('submit', SubmitType::class);
}

documentation查看更多详情。

【讨论】:

  • 当我这样做时,它只是在表单中显示字符串“Reviews”,而不是它的所有字段(userID、posted、bookID 和 comment)
  • 这是正常行为。您需要制作一个“添加”按钮,您的表单用户可以按下该按钮来添加新评论。只有当您编辑已有评论的现有书籍时,您才会看到评论。我认为你必须完成这门课程:symfony.com/doc/current/form/form_collections.html
【解决方案2】:

为了显示特定图书的评论,您需要在Book 实体中实现OneToMany 关系(作为反面),并在Review 实体中实现ManyToOne 关系(作为拥有方)。

我已经搜索了完整的示例,但找不到任何示例,所以这是我的尝试:

1) 创建BookReview 实体,没有任何关系,并在数据库中创建它们。如果您尝试在关系旁边创建表,并且这些表尚未存在于数据库中,则会出现错误。

2) 现在您可以创建关系了

# AppBundle\Entity\Book.php
use Doctrine\Common\Collections\ArrayCollection;
...
class Book
...
/**
 * @ORM\OneToMany(targetEntity="Review", mappedBy="book")
 */
private $reviews;

public function __construct()
{
    $this->reviews = new ArrayCollection();
}
//... getters and setters for extra fields you might have
/**
 * @return ArrayCollection|Review[]
 */
public function getReviews()
{
    return $this->reviews;
}
// Notice here you don't need the setReviews() setter!



# AppBundle/Entity/Review.php
use AppBundle\Entity\Book;
...
class Review
...
/**
 * @ORM\ManyToOne(targetEntity="Book", inversedBy="reviews")
 */
private $book;
//... getters and setters for extra fields you might have
/**
 * @return Review
 */
public function getBook()
{
    return $this->book;
}

/**
 * Notice here is passed the entire book object
 * @param Book $book
 * @return $this
 */
public function setBook(Book $book)
{
    $this->book = $book;
    return $this;
}

3) 通过创建迁移或使用doctrine:schema:update --force 命令来应用这些关系。

4) 根据实体创建表单

-> BookType:php bin/console doctrine:generate:form AppBundle:Book

-> ReviewType:php bin/console doctrine:generate:form AppBundle:Review,您需要使用 EntityType 才能获得属于该评论数组的图书。

# AppBundle/Form/ReviewType.php
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Doctrine\ORM\EntityRepository;
...
class ReviewType extends AbstractType
...
->add('book', EntityType::class, [
    'class' => 'AppBundle:Book',
    'placeholder' => ' ',
    'query_builder' => function(EntityRepository $er) {
        return $er->createQueryBuilder('b');
    },
    'choice_label' => function($book){
        return $book->getId();// in the <select> options put the ids from Book entity
    },
    'multiple' => false, // a user can select only one option per submission
    'expanded' => false // options will be presented in a <select> dropdown; set this to true, to present the data in checkboxes
])

5) 在控制器中创建和保存书籍的操作:

# AppBundle/Controller/DefaultController.php
use AppBundle\Entity\Book;
use AppBundle\Form\BookType;
...
/**
 * @Route("/book", name="book")
 */
public function bookAction(Request $request)
{
    $book = new Book();
    $form = $this->createForm(BookType::class, $book, [
        'action' => $this->generateUrl('book'),
        'method' => 'POST'
    ]);
    $form->handleRequest($request);
    if ($form->isSubmitted() && $form->isValid()) {
        $em = $this->getDoctrine()->getManager();
        $em->persist($book);
        $em->flush();

        return $this->redirectToRoute('book');
    }
    return $this->render('default/book.html.twig', ['form'=>$form->createView()]);
}

6) 在控制器中创建和保存评论的操作

# AppBundle/Controller/DefaultController.php
use AppBundle\Entity\Review;
use AppBundle\Form\ReviewType;
...
/**
 * @Route("/review", name="review")
 */
public function reviewAction(Request $request)
{
    $review = new Review();
    $form = $this->createForm(ReviewType::class, $review, [
        'action' => $this->generateUrl('review'),
        'method' => 'POST'
    ]);
    $form->handleRequest($request);
    if ($form->isSubmitted() && $form->isValid()) {
        $em = $this->getDoctrine()->getManager();
        $em->persist($review);
        $em->flush();

        return $this->redirectToRoute('review');
    }
    return $this->render('default/review.html.twig', ['form'=>$form->createView()]);
}

7) 用于显示特定书籍的评论:

# AppBundle/Controller/DefaultController.php
/**
 * @Route("/", name="homepage")
 */
public function indexAction()
{
    $reviews = $this->getDoctrine()->getRepository('AppBundle:Review')->findAll();

    if (!$reviews) {
        throw $this->createNotFoundException('No review(s) found!');
    }

    return $this->render('default/index.html.twig',['reviews'=>$reviews]);
}

8) 显示评论的视图(对于书籍和评论,只需打印表格,所以我不会发布代码,因为这很琐碎)

# app/Resources/views/default/index.html.twig
{% extends 'base.html.twig' %}

{% block body %}
    {% for review in reviews %}
        {{ review.comment ~ '-' ~ review.book.name }}
    {% endfor %}
{% endblock %}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多