【问题标题】:How do I perform validation on embedded form PHP/Symfony?如何对嵌入式表单 PHP/Symfony 执行验证?
【发布时间】:2017-02-24 18:46:42
【问题描述】:

我有三个实体:用户、评论、文章。用户可以发表评论/文章。

在我的文章控制器中,我有一个名为 commentAction 的方法,它应该返回评论表单。我在文章显示模板中调用了这个控制器。它有效,但是当我尝试验证表单时出现问题。

我想将用户返回到文章显示页面,并显示评论表单错误。

两个问题:表单将我们带到commentAction 而不是回到showAction。此外,由于某种原因,我无法显示验证错误。

我已经合并了一个转发器(无论如何它似乎都不能正常工作)。有人能告诉我正确的方法吗???

非常感谢!

附:我是 Symfon 的新手,所以如果我违反了任何最佳实践,如果你能提醒我,如果你让我知道,我将不胜感激:)。

评论实体:

<?php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
/**
 * Comment
 *
 * @ORM\Table(name="comment")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\CommentRepository")
 */
class Comment
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var int $rating
     *
     * @ORM\Column(name="rating", type="smallint")
     * @Assert\NotBlank()
     */
    private $rating;

    /**
     * @var string
     *
     * @ORM\Column(name="title", type="string", length=255)
     */
    private $title;

    /**
     * @ORM\ManyToOne(targetEntity="User", inversedBy="comments")
     * @ORM\JoinColumn(name="user_id", referencedColumnName="id")
     */
    private $user;

    /**
     * @ORM\ManyToOne(targetEntity="Article", inversedBy="comments")
     * @ORM\JoinColumn(name="article_id", referencedColumnName="id")
     */
    private $article;

    /**
     * @var string
     *
     * @ORM\Column(name="comment", type="text", nullable=true)
     */
    private $comment;


    /**
     * Get id
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set rating
     *
     * @param integer $rating
     *
     * @return Comment
     */
    public function setRating($rating)
    {
        $this->rating = $rating;

        return $this;
    }

    /**
     * Get rating
     *
     * @return int
     */
    public function getRating()
    {
        return $this->rating;
    }

    /**
     * Set title
     *
     * @param string $title
     *
     * @return Comment
     */
    public function setTitle($title)
    {
        $this->title = $title;

        return $this;
    }

    /**
     * Get title
     *
     * @return string
     */
    public function getTitle()
    {
        return $this->title;
    }

    /**
     * Set userId
     *
     * @param integer $userId
     *
     * @return Comment
     */
    public function setUserId($userId)
    {
        $this->userId = $userId;

        return $this;
    }

    /**
     * Get userId
     *
     * @return int
     */
    public function getUserId()
    {
        return $this->userId;
    }

    /**
     * Set comment
     *
     * @param string $comment
     *
     * @return Comment
     */
    public function setComment($comment)
    {
        $this->comment = $comment;

        return $this;
    }

    /**
     * Get comment
     *
     * @return string
     */
    public function getComment()
    {
        return $this->comment;
    }

    /**
     * Set user
     *
     * @param \AppBundle\Entity\User $user
     *
     * @return Comment
     */
    public function setUser(\AppBundle\Entity\User $user = null)
    {
        $this->user = $user;

        return $this;
    }

    /**
     * Get user
     *
     * @return \AppBundle\Entity\User
     */
    public function getUser()
    {
        return $this->user;
    }

    /**
     * Set article
     *
     * @param \AppBundle\Entity\Article $article
     *
     * @return Comment
     */
    public function setArticle(\AppBundle\Entity\Article $article = null)
    {
        $this->article = $article;

        return $this;
    }

    /**
     * Get article
     *
     * @return \AppBundle\Entity\User
     */
    public function getArticle()
    {
        return $this->article;
    }
}

文章管理员

<?php

namespace AppBundle\Controller;

use AppBundle\Entity\Article;
use AppBundle\Entity\Comment;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Request;
use AppBundle\General\HelperClass;

use AppBundle\Form\CommentType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;

/**
 * Article controller.
 *
 * @Route("article")
 */
class ArticleController extends Controller
{
    /**
     * Show all article entities.
     *
     * @Route("/", name="article_index")
     * @Method("GET")
     */
    public function indexAction(Request $request)
    {
        return $this->render('article/index.html.twig');
    }

    /**
     * Lists all article entities, optionally sorted.
     *
     * @Route("/list", name="article_list")
     * @Method("GET")
     */
    public function listAction(Request $request)
    {
        //if we're passing a sort_by it'll be an embed in twig template.
        $sortBy = $request->get('sort_by');

        $em = $this->getDoctrine()->getManager();

        if('average-rating' === $sortBy){
            $sortBy = "avg_rating";
            $articles = $em->getRepository('AppBundle:Article')->getArticlesByAverageRating($sortBy);
        } else {
            $sortBy = "name";
            $articles = $em->getRepository('AppBundle:Article')->getArticlesByAverageRating($sortBy);
        }

        return $this->render('article/list.html.twig', array(
            'articles' => $articles,
        ));
    }

   protected function getComment(\AppBundle\Entity\User $user, \AppBundle\Entity\Article $article, \AppBundle\Entity\Comment $comment){

        $em = $this->getDoctrine()->getManager();
        $userId = $user->getId();

        $existingComment = $em->getRepository('AppBundle:Comment')->getCommentByUserIdAndArticleId($user, $article);

        if($existingComment) {
            $existingComment->setRating($comment->getRating());
            $existingComment->setTitle($comment->getTitle());
            $existingComment->setComment($comment->getComment());
            $comment = $existingComment;
        }

        return $comment;

    }

    /**
     * Creates a new article entity.
     *
     * @Route("/new", name="article_new")
     * @Method({"GET", "POST"})
     */
    public function newAction(Request $request)
    {
        $article = new Article();
        $form = $this->createForm('AppBundle\Form\ArticleType', $article);



        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {



            $em = $this->getDoctrine()->getManager();
            $user = $this->getUser();
            //Set the user
            $article = $form->getData();
            $article->setUser($user);
            //Set Created Date
            $date = new \DateTime("now");
            $article->setCreatedDate($date);
            $em->persist($article);
            $em->flush($article);




            return $this->redirectToRoute('article_show', array('id' => $article->getId()));

        }

        return $this->render('article/new.html.twig', array(
            'article' => $article,
            'form' => $form->createView(),
        ));
    }

    /**
     * Finds and displays a article entity.
     *
     * @Route("/{id}", name="article_show")
     * @Method("GET")
     */
    public function showAction(Article $article)
    {

        $deleteForm = $this->createDeleteForm($article);

        return $this->render('article/show.html.twig', array(
            'article' => $article,
            'delete_form' => $deleteForm->createView(),
        ));
    }

    /**
     * The comment form for articles
     *
     * @Route("/{id}/comment", name="article_comment")
     * @Method({"GET", "POST"})
     */
    public function commentAction(Request $request, Article $article)
    {
        $comment = new Comment();
        //Build the comment form. 

        $commentForm = $this->createFormBuilder($comment)
            ->add('comment', CommentType::class, array("label" => FALSE))
            ->setAction($this->generateUrl('article_comment', array('id' =>$article->getId())))
            ->getForm();

        $commentForm->handleRequest($request);

//THIS IS MY FORWARDER BUT I SEEM TO LOSE ALL FORM DATA WHEN I DO THIS SO I DON"T THINK IT"S RIGHT!!
        if ($commentForm->isSubmitted() && !$commentForm->isValid()) {
            return $this->forward(
                'AppBundle:Article:show',
                array(
                    'form'  => $commentForm->createView(),
                    'article' => $article,
                )
            );
        }

        if ($commentForm->isSubmitted() && $commentForm->isValid()) {

            //Update existing user or create new
            $em = $this->getDoctrine()->getManager();
            $comment = $commentForm->getData()->getComment();
            $user = $this->getUser();

            $comment = $this->getComment($user, $article, $comment);

            //Set the user and article for the comment.
            $comment->setUser($user);
            $comment->setArticle($article);

            $em->persist($comment);
            $em->flush($comment);

            $this->getDoctrine()->getManager()->flush();
            return $this->redirectToRoute('article_show', array('id' => $article->getId()));
        }

        return $this->render('article/comment.html.twig', array(
            'form' => $commentForm->createView(),
        ));
    }

    /**
     * Displays a form to edit an existing article entity.
     *
     * @Route("/{id}/edit", name="article_edit")
     * @Method({"GET", "POST"})
     */
    public function editAction(Request $request, Article $article)
    {
        $deleteForm = $this->createDeleteForm($article);
        $editForm = $this->createForm('AppBundle\Form\ArticleType', $article);
        $editForm->handleRequest($request);

        if ($editForm->isSubmitted() && $editForm->isValid()) {
            $this->getDoctrine()->getManager()->flush();

            return $this->redirectToRoute('article_edit', array('id' => $article->getId()));
        }

        return $this->render('article/edit.html.twig', array(
            'article' => $article,
            'edit_form' => $editForm->createView(),
            'delete_form' => $deleteForm->createView(),
        ));
    }

    /**
     * Deletes a article entity.
     *
     * @Route("/{id}", name="article_delete")
     * @Method("DELETE")
     */
    public function deleteAction(Request $request, Article $article)
    {
        $form = $this->createDeleteForm($article);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->remove($article);
            $em->flush($article);
        }

        return $this->redirectToRoute('article_index');
    }

    /**
     * Creates a form to delete a article entity.
     *
     * @param Article $article The article entity
     *
     * @return \Symfony\Component\Form\Form The form
     */
    private function createDeleteForm(Article $article)
    {
        return $this->createFormBuilder()
            ->setAction($this->generateUrl('article_delete', array('id' => $article->getId())))
            ->setMethod('DELETE')
            ->getForm()
        ;
    }
}

显示文章分支

{% extends 'base.html.twig' %}
{% block body_id 'articlepage' %}
{% block body %}

<h1>Article: {{ article.name }}</h1>

<div class="well"><div class="media">
    <div class="media-left media-top">
        <img class="media-object" src="{{ article.thumbnail }}">
    </div>
    <div class="media-body">

        <h4 class="media-heading">{{ article.name }}</h4>
        <p>{{ article.description }}</p>
    </div>
</div></div>

{{ render(controller('AppBundle:Comment:index', {'article_id': article.id})) }}

{% if is_granted('ROLE_USER') -%}
    <h2>Submit a new comment:</h2>
    {{ render(controller('AppBundle:Article:comment', {'id': article.id})) }}
{% else %}
    <h3>Log In To Leave A Comment!</h3>
    <p>Click <a href="{{ path('fos_user_security_login') }}">here</a> to log in or <a href="{{ path('fos_user_registration_register') }}">here</a> to register</p>
{% endif %}

{% endblock %}

评论文章树枝

{% extends 'base.html.twig' %}
{% form_theme form 'form/fields.html.twig' %}

{% block body %}
    {{ form_start(form) }}{{ form_errors(form.comment.comment) }}{{form_errors(form.comment.title) }} 
    <div class="form-group">{{ form_row(form.comment.title) }}</div>
    <div class="form-group">{{ form_row(form.comment.rating) }}</div>
    <div class="form-group">{{ form_row(form.comment.comment) }}</div>
    <input class="btn btn-default" type="submit" value="Create" />
    {{ form_end(form) }}
{% endblock %}

【问题讨论】:

    标签: php forms validation symfony


    【解决方案1】:

    将您的显示操作放在您的 createFormBuilder 中的 ->setAction() 中,而不是像您目前拥有的评论操作。

    ->setAction($this->generateUrl('article_show', array('id' =>$article->getId())))
    

    您需要在显示操作中处理表单解析。我总是建议使用错误冒泡在页面顶部显示所有错误。在您的 createFormBuilder 中,只需修改您的添加:

    >add('comment', CommentType::class, array("label" => false, 'error_bubbling' => true))
    

    然后在 Twig 中将其放在表单上方:

    {% if form_errors(form)|length > 10 %}
        <div class="col-md-10 col-md-offset-1">
            <div class="alert alert-danger fade-in">
                {{ form_errors(form) }}
            </div>
        </div>
    {% endif %}
    

    【讨论】:

      【解决方案2】:

      我假设您可以在一篇文章中添加许多 cmets。那么您在这些实体之间就有了一对多的关系。这必须在使用注释的实体声明中定义。详情见这篇文章:http://symfony.com/doc/current/doctrine/associations.html

      使用此定义,您可以为实体评论创建单独的表单类型。在实体 Article 的表单类型中,您将字段“comment”定义为 CollectionType。 Symfony 使用实体 Comment 的表单类型来呈现实体 Article 中的字段注释。详情见这篇文章:https://symfony.com/doc/current/form/form_collections.html

      【讨论】:

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