如何在嵌入式表单PHP / Symfony上执行验证?

时间:2017-02-24 18:46:43

标签: php forms validation symfony

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

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

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

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

我已经合并了一个货运代理(无论如何它似乎都不正常)。有人能告诉我正确的方法吗?

非常感谢!

P.S。我是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 %}

评论文章Twig

{% 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 %}

2 个答案:

答案 0 :(得分:0)

将您的show动作放在createFormBuilder中的 - &gt; setAction()中,而不是像您当前拥有的那样进行评论操作。

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

您需要在show动作中处理解析表单。我总是建议使用错误冒泡来显示页面顶部的所有错误。在您的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 %}

答案 1 :(得分:0)

我假设您可以在文章中添加许多评论。然后,您在这些实体之间拥有一对多关系。这必须在使用注释的实体声明中定义。有关详细信息,请参阅此文章:http://symfony.com/doc/current/doctrine/associations.html

使用此定义,您可以为实体Comment创建单独的表单类型。在实体文章的表单类型中,您将字段“comment”定义为 CollectionType 。 Symfony使用实体Comment的表单类型在实体Article中呈现字段注释。有关详细信息,请参阅此文章:https://symfony.com/doc/current/form/form_collections.html