我目前正在学习PHP和Symfony。我正在尝试使用登录用户创建的食谱制作食谱。在我的食谱创建页面中,我有一个表单类型,其中包含几个TextType
,一个CollectionType
和一个SubmitType
。
这个想法是,当用户创建食谱时,他/她可以将成分列表添加到创建的食谱中。我的问题是我无法保留我创建的实体数组。我收到此消息:
关联字段"AppBundle\Entity\Recipe#$ingredients"的预期值为"Doctrine\Common\Collections\Collection|array",而是使用"字符串"。
我尝试创建一个addIngredient()
函数,并在__construct()
函数中创建了一个新ArrayCollection
。 我不知道这是否只是我盯着这个问题太久了。
以下是我的实体:
配方实体
namespace AppBundleEntity;
use DoctrineCommonCollectionsArrayCollection;
use DoctrineCommonCollectionsCollection;
use DoctrineORMMapping as ORM;
/**
*@ORMEntity
*@ORMTable(name="Recipees")
*/
class Recipe{
/**
*@ORMId
*@ORMGeneratedValue(strategy="AUTO")
*@ORMColumn(type="integer")
*/
protected $id;
/**
* @ORMManyToOne(targetEntity="User", inversedBy="recipe")
* @ORMJoinColumn(name="user_id", referencedColumnName="id",
* nullable=false, onDelete="CASCADE")
*/
private $user;
/**
*@ORMColumn(type="string", name="title", length=100)
*/
private $title;
/**
* @ORMOneToMany(targetEntity="AppBundleEntityIngredients",
* mappedBy="recipe")
* @ORMJoinTable(name="ingredients")
*/
private $ingredients;
/**
*@ORMColumn(type="text", name="instructions")
*/
private $instructions;
/**
*@ORMColumn(type="datetime", name="created_at")
*@ORMGeneratedValue(strategy="AUTO")
*/
private $created_at;
/**
*@ORMColumn(type="datetime", name="modified_at")
*@ORMGeneratedValue(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 AppBundleEntityUser $user
*
* @return Recipe
*/
public function setUser(User $user = null)
{
$this->user = $user;
return $this;
}
/**
* Get rUser
*
* @return AppBundleEntityUser
*/
public function getUser()
{
return $this->user;
}
}
成分实体
namespace AppBundleEntity;
use DoctrineORMMapping as ORM;
/**
* @ORMEntity
* @ORMTable(name="ingrediens")
*/
class Ingredients
{
/**
* @ORMId
* @ORMGeneratedValue(strategy="AUTO")
* @ORMColumn(type="integer")
*/
protected $id;
/**
* @ORMManyToOne(targetEntity="AppBundleEntityRecipe", inversedBy="ingredients")
* @ORMJoinColumn(name="recipe_id", referencedColumnName="id", nullable=true, onDelete="CASCADE")
*/
private $recipe;
/**
* @ORMColumn(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 AppBundleEntityIngredients;
use AppBundleEntityRecipe;
use AppBundleFormAddRecipeFormType;
use SensioBundleFrameworkExtraBundleConfigurationRoute;
use SymfonyBundleFrameworkBundleControllerController;
use SymfonyComponentHttpFoundationRequest;
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 AppBundleForm;
use SymfonyComponentFormAbstractType;
use SymfonyComponentFormExtensionCoreTypeCollectionType;
use SymfonyComponentFormExtensionCoreTypeSubmitType;
use SymfonyComponentFormExtensionCoreTypeTextareaType;
use SymfonyComponentFormExtensionCoreTypeTextType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolver;
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' => 'AppBundleEntityRecipe']);
}
public function getBlockPrefix()
{
return 'app_bundle_new_recipe_form_type';
}
}
我的树枝(如果有帮助的话(
{% 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 %}
在食谱中试试这个
public function addIngredients($ingredients){
$this->ingredients[] = $ingredients;
$ingredients->setRecipe($this);
用这个改变你的表格
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,
));
}