简体   繁体   中英

Symfony 3.4 - Doctrine ManyToMany association error

I'm working on a simple Symfony API and I'm having trouble setting a relation between two entities. I have this two classes: Recipe and Ingredient. A Recipe can have many ingredients and an ingredient can be present in many recipes so I used a ManyToMany association.

This is my Recipe class:

namespace RecipesBundle\Entity;

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

/**
 * Recipe
 *
 * @ORM\Table(name="recipe")
 * @ORM\Entity(repositoryClass="RecipesBundle\Repository\RecipeRepository")
 */
class Recipe
{
/**
 * @var int
 *
 * @ORM\Column(name="id", type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="AUTO")
 */
private $id;

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

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

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

/**
 * @ORM\ManyToMany(targetEntity="Ingredient", inversedBy="recipes")
 * @ORM\JoinTable(name="recipes_ingredients")
 */
private $ingredients;

public function __construct() {
    $this->ingredients = new ArrayCollection();
}

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

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

    return $this;
}

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

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

    return $this;
}

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

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

    return $this;
}

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

/**
 * Set ingredients
 * 
 * @param array $ingredients
 * @return Recipe
 */
public function setIngredients($ingredients) {

    foreach($ingredients as $ingredient) {
        $this->ingredients->add($ingredient);
    }

    return $this;
}

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

}

This is my Ingredient class:

namespace RecipesBundle\Entity;

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

/**
 * Ingredient
 *
 * @ORM\Table(name="ingredient")
 * 
@ORM\Entity(repositoryClass="RecipesBundle\Repository\IngredientRepository")
 */
class Ingredient
{
/**
 * @var int
 *
 * @ORM\Column(name="id", type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="AUTO")
 */
private $id;

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

/**
 * @var int
 *
 * @ORM\Column(name="amount", type="integer")
 */
private $amount;

/**
 * @ORM\ManyToMany(targetEntity="Recipe", mappedBy="ingredients")
 */
private $recipes;

public __construct() {
    $this->recipes = new ArrayCollection();
}

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

/**
 * Set name
 *
 * @param string $name
 *
 * @return Ingredient
 */
public function setName($name)
{
    $this->name = $name;

    return $this;
}

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

/**
 * Set amount
 *
 * @param integer $amount
 *
 * @return Ingredient
 */
public function setAmount($amount)
{
    $this->amount = $amount;

    return $this;
}

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

}

And this is my controller:

class RecipeController extends Controller
{
/**
 * @Route("/recipes")
 */
public function recipesAction(Request $request)
{
    switch($request->getMethod()) {
        case 'GET':

            $recipes = $this->getDoctrine()->getRepository(Recipe::class)->findAll();
            $return = $recipes;

            break;
        case 'POST':
            $recipe = new Recipe();
            $recipeData = json_decode($request->getContent(), true);

            $recipe->setName($recipeData['name']);
            $recipe->setDescription($recipeData['description']);
            $recipe->setImage($recipeData['imagePath']);

            $ingredients = $recipeData['ingredients'];

            //var_dump($ingredients);die;

            $recipe->setIngredients($ingredients);

            //var_dump($recipe);die;

            $em = $this->getDoctrine()->getManager();
            $em->persist($recipe);
            $em->flush();

            $return = 'Recipe saved successfully';

            break;
        case 'PUT':

            $recipes = json_decode($request->getContent(), true);

            $em = $this->getDoctrine()->getManager();
            foreach($recipes as $updating_recipe) {

                $recipe = $this->getDoctrine()->getRepository(Recipe::class)->findOneBy(array('name' => $updating_recipe['name']));

                if($recipe)
                {
                    $recipe->setName($updating_recipe['name']);
                    $recipe->setDescription($updating_recipe['description']);
                    $recipe->setImage($updating_recipe['image']);
                    $recipe->setIngredients($updating_recipe['ingredients']);

                    $em->flush();
                }
            }

            $return = 'Recipes saved successfully';
            break;
        case 'DELETE':
            break;
    }
    return new JsonResponse($return);
}

}

The problem occurs when I try to save a new recipe (post request). I get the following error:

Expected value of type "Doctrine\\Common\\Collections\\Collection|array" for association field "RecipesBundle\\Entity\\Recipe#$ingredients", got "array" instead.

I don't understand why I get this error if I use the setIngredients correctly to add the ingredients to the array collection.

Any ideas on what could be wrong? Thanks in advance

EDIT 1:

I'm adding the dump of the ingredients as requested:

array (size=1) 
    0 => 
        array (size=2) 
            'name' => string 'Spaghetti' (length=9)
            'amount' => int 10

Ok the problem is solved. As Sami indicated, I had to iterate through the ingredients that come in the request and create an Ingredient object for each one. Then add them to an ArrayCollection and set it using $recipe->setIngredients();

Thank you very much for your help.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM