通过CollectionType

时间:2017-07-21 14:17:07

标签: php entity-framework symfony doctrine-orm doctrine

我目前正在学习PHP和Symfony。我正在尝试用登录用户创建的食谱制作食谱。在我的食谱创建页面中,我的表单类型包含几个TextTypeCollectionTypeSubmitType

这个想法是,当用户创建食谱时,他/她可以向创建的食谱添加成分列表。我的问题是我不能坚持我创建的实体数组。我收到这条消息:

  

类型" Doctrine \ Common \ Collections \ Collection | array"的预期值对于协会领域" AppBundle \ Entity \ Recipe#$ ingredients",得到"字符串"代替。

我尝试创建addIngredient()函数,并在ArrayCollection函数中创建了一个新的__construct()。我不知道这是不是我长时间盯着这个问题。

以下是我的实体:

配方实体

namespace AppBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;

/**
*@ORM\Entity
*@ORM\Table(name="Recipees")
*/

class Recipe{

    /**
    *@ORM\Id
    *@ORM\GeneratedValue(strategy="AUTO")
    *@ORM\Column(type="integer")
    */

    protected $id;    

    /**
     * @ORM\ManyToOne(targetEntity="User", inversedBy="recipe")
     * @ORM\JoinColumn(name="user_id", referencedColumnName="id", 
     * nullable=false, onDelete="CASCADE")
     */
    private $user;

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

    /**
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\Ingredients", 
     * mappedBy="recipe")
     * @ORM\JoinTable(name="ingredients")
     */

    private $ingredients;
    /**
    *@ORM\Column(type="text", name="instructions")
    */

    private $instructions;

    /**
    *@ORM\Column(type="datetime", name="created_at")
    *@ORM\GeneratedValue(strategy="AUTO")
    */

    private $created_at;

    /**
    *@ORM\Column(type="datetime", name="modified_at")
    *@ORM\GeneratedValue(strategy="AUTO")
    */

    private $modified_at;

    public function __construct() {
        $this->ingredients = new ArrayCollection();
        $this->created_at = new \DateTime();
        $this->modified_at = new \DateTime('now');
    }

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

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

        return $this;
    }

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


/**
 * @return mixed
 */
public function getIngredients()
{
    return $this->ingredients;
}


public function addIngredients($ingredients){
    $this->ingredients->add($ingredients);
    return $this;
}

/**
 * @param mixed $ingredients
 */
public function setIngredients($ingredients)
{
    $this->ingredients = $ingredients;
}

/**
 * Set instructions
 *
 * @param string $instructions
 *
 * @return Recipe
 */
public function setInstructions($instructions)
{
    $this->instructions = $instructions;

    return $this;
}

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

/**
 * Set createdAt
 *
 * @param \DateTime $createdAt
 *
 * @return Recipe
 */
public function setCreatedAt($createdAt)
{
    $this->created_at = $createdAt;

    return $this;
}

/**
 * Get createdAt
 *
 * @return \DateTime
 */
public function getCreatedAt()
{
    return $this->created_at;
}

/**
 * Set modifiedAt
 *
 * @param \DateTime $modifiedAt
 *
 * @return Recipe
 */
public function setModifiedAt($modifiedAt)
{
    $this->modified_at = $modifiedAt;

    return $this;
}

/**
 * Get modifiedAt
 *
 * @return \DateTime
 */
public function getModifiedAt()
{
    return $this->modified_at;
}

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

    return $this;
}

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

成分实体

    namespace AppBundle\Entity;
    use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="ingrediens")
 */
class Ingredients
{


    /**
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     * @ORM\Column(type="integer")
     */
    protected $id;

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Recipe", inversedBy="ingredients")
     * @ORM\JoinColumn(name="recipe_id", referencedColumnName="id", nullable=true, onDelete="CASCADE")
     */
    private $recipe;

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


    /**
     * @return mixed
     */
    public function getRecipe()
    {
        return $this->recipe;
    }

    /**
     * @param mixed $recipe
     */
    public function setRecipe($recipe)
    {
        $this->recipe = $recipe;
    }

    /**
     * @return mixed
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @param mixed $name
     */
    public function setName($name)
    {
        $this->name = $name;
    }

我的控制器

use AppBundle\Entity\Ingredients;
use AppBundle\Entity\Recipe;
use AppBundle\Form\AddRecipeFormType;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;


    class RecipeController extends Controller
    {


        /**
         * @Route("/recipe/new", name = "newRecipe")
         */

        public function addRecipe(Request $request){


            $ingredients = new Ingredients();
            $recipe = new Recipe();
            $user = $this->getUser();
            $recipe->setUser($user);


            $formRecipe = $this->createForm(AddRecipeFormType::class, $recipe);


            $formRecipe->handleRequest($request);

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

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

                $recipe->addIngredients($ingredients);
                $em->persist($recipe);
                $em->flush();

                dump($recipe);
                die;

               //  return $this->redirectToRoute('fos_user_profile_show');
            }


            return $this->render('/CookBook/addRecipe.html.twig', [
                'newRecipe' => $formRecipe->createView(),
            ]);

        }

我的表格

namespace AppBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class AddRecipeFormType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('title', TextType::class)
            ->add('ingredients', CollectionType::class, array(
                'entry_type' => TextType::class,
                'allow_add' => true,
                'prototype' => true

            ))
            ->add('instructions', TextareaType::class)
            ->add('submit', SubmitType::class, array('label' => 'Create Recipe'));
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(['data' => 'AppBundle\Entity\Recipe']);
    }

    public function getBlockPrefix()
    {
        return 'app_bundle_new_recipe_form_type';
    }
}

My Twig(如果有帮助的话)

{% extends 'base.html.twig' %}

{% block body %}
    <h1>Create your own Recipe</h1>

    {{  form_start (newRecipe) }}
    {{ form_row(newRecipe.title) }}
    <ul id="ingredient-fields-list"
        data-prototype="{{ form_row(newRecipe.ingredients.vars.prototype)|e }}">
        {% for Recipe in newRecipe.ingredients %}
            <li>
                {{ form_errors(newRecipe.ingredients) }}
                {{ form_row(newRecipe.ingredients) }}
            </li>
        {% endfor %}
    </ul>
    <a href="#" id="add-another-ingredient">Add Ingredient</a>
     {{ form_widget(newRecipe) }}

     {{ form_end(newRecipe) }}




{% endblock %}

{% block javascripts %}
    <script type="text/javascript">
        // keep track of how many email fields have been rendered
        var IngredientCount =  '{{ newRecipe.ingredients|length }}';

        jQuery(document).ready(function() {
            jQuery('#add-another-ingredient').click(function(e) {
                e.preventDefault();

                var ingredientList = jQuery('#ingredient-fields-list');

                // grab the prototype template
                var newWidget = ingredientList.attr('data-prototype');
                // replace the "__name__" used in the id and name of the prototype
                // with a number that's unique to your emails
                // end name attribute looks like name="contact[emails][2]"
                newWidget = newWidget.replace("Ingredients", IngredientCount);
                IngredientCount++;

                // create a new list element and add it to the list
                var newLi = jQuery('<li></li>').html(newWidget);
                newLi.appendTo(ingredientList);
            });
        })
    </script>
{% endblock %}

2 个答案:

答案 0 :(得分:0)

在Recipe中尝试这个

 public function addIngredients($ingredients){
        $this->ingredients[] = $ingredients;
    $ingredients->setRecipe($this);

答案 1 :(得分:0)

使用此

更改您的表单
public function buildForm(FormBuilderInterface $builder, array $options) {
    $builder ->add('title', TextType::class)
        ->add('ingredients', CollectionType::class, array( 'entry_type' => EntityType::class,
            'allow_add' => true, 'prototype' => true ))
        ->add('instructions', TextareaType::class)
        ->add('submit', SubmitType::class, array('label' => 'Create Recipe'));

}
public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults(array(
        'data_class' => Ingredients::class,
    ));
}