php - 该属性和方法之一都不存在并且在类“Symfony\Component\Form\FormView”中具有公共访问权限
问题描述
尝试创建新的“类别”时出现此错误,它可以正常工作,但现在不行。修改“食谱”表单以添加其他关系 ManyToMany 后出现错误
Blockquote 属性 "category" 和方法 "category()"、"getcategory()"/"iscategory()"/"hascategory()" 或 "__call()" 都不存在并且在类 "Symfony" 中具有公共访问权限\组件\窗体\窗体视图”。
分类.php
<?php
namespace App\Entity;
use App\Repository\CategoryRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass="App\Repository\CategoryRepository", repositoryClass=CategoryRepository::class)
*/
class Category
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $title;
/**
* @ORM\Column(type="string", length=1000, nullable=true)
*/
private $description;
/**
* Bidirectional (INVERSE SIDE)
*
* @ORM\ManyToMany(targetEntity=Recipe::class, mappedBy="category")
*/
private $recipes;
public function __construct()
{
$this->recipes = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): self
{
$this->description = $description;
return $this;
}
/**
* @return Collection|Recipe[]
*/
public function getRecipes(): Collection
{
return $this->recipes;
}
public function addRecipe(Recipe $recipe): self
{
if (!$this->recipes->contains($recipe)) {
$this->recipes[] = $recipe;
$recipe->addCategory($this);
}
return $this;
}
public function removeRecipe(Recipe $recipe): self
{
if ($this->recipes->removeElement($recipe)) {
$recipe->removeCategory($this);
}
return $this;
}
public function __toString()
{
return $this->title;
}
}
食谱.php
<?php
namespace App\Entity;
use App\Repository\RecipeRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=RecipeRepository::class)
*/
class Recipe {
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $title;
/**
* @ORM\Column(type="string", length=1000)
*/
private $description;
/**
* @ORM\Column(type="datetime")
*/
private $date;
/**
* Bidirectional - Many recipes have Many categories (OWNING SIDE)
*
* @ORM\ManyToMany(targetEntity=Category::class, inversedBy="recipes")
*/
private $category;
/**
* @ORM\OneToMany(targetEntity=Step::class, mappedBy="recipe", cascade={"persist"})
*/
private $steps;
public function __construct() {
$this->category = new ArrayCollection();
$this->steps = new ArrayCollection();
}
public function getId(): ?int {
return $this->id;
}
public function getTitle(): ?string {
return $this->title;
}
public function setTitle(string $title): self {
$this->title = $title;
return $this;
}
public function getDate(): ?\DateTimeInterface {
return $this->date;
}
public function setDate(\DateTimeInterface $date): self {
$this->date = $date;
return $this;
}
public function getDescription(): ?string {
return $this->description;
}
public function setDescription(string $description): self {
$this->description = $description;
return $this;
}
/**
* @return Collection|Category[]
*/
public function getCategory(): Collection {
return $this->category;
}
public function addCategory(Category $category): self {
if (!$this->category->contains($category)) {
$this->category[] = $category;
}
return $this;
}
public function removeCategory(Category $category): self {
$this->category->removeElement($category);
return $this;
}
public function hasCategory() {
if($this->category->isEmpty()){
return true;
}
return false;
}
/**
* @return Collection|Step[]
*/
public function getSteps(): Collection {
return $this->steps;
}
public function addStep(Step $step): self {
if (!$this->steps->contains($step)) {
$this->steps[] = $step;
$step->setRecipe($this);
}
return $this;
}
public function removeStep(Step $step): self {
if ($this->steps->removeElement($step)) {
// set the owning side to null (unless already changed)
if ($step->getRecipe() === $this) {
$step->setRecipe(null);
}
}
return $this;
}
public function __toString() {
return $this->title;
}
}
new.html.twig(用于新类别)
{% extends 'base.html.twig' %}
{% block title %}New Category{% endblock %}
{% block body %}
<h1>New Category</h1>
{{ form(form) }}
{% endblock %}
new.html.twig(用于新配方)
{% extends 'base.html.twig' %}
{% block title %}New Recipe{% endblock %}
{% block body %}
<h1>New Recipe</h1>
{{ form_start(form) }}
{{ form_row(form.title) }}
{{ form_row(form.description) }}
{{ form_widget(form.category) }}
<ul class="steps list-unstyled" data-prototype="{{ form_widget(form.steps.vars.prototype)|e }}">
{{ form_end(form) }}
{% endblock %}
{% block javascripts %}
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
<script>
var $collectionHolder;
// setup an "add a tag" link
var $saveButton = $('#recipe_save');
var $addStepButton = $('<button type="button" class="add_step_link btn btn-secondary btn-sm mb-2 mt-2">Add Step</button>');
var $newLinkLi = $('<li></li>');
jQuery(document).ready(function () {
// Get the ul that holds the collection of tags
$collectionHolder = $('ul.steps');
$collectionHolder.before($addStepButton);
// add the "add a tag" anchor and li to the tags ul
$collectionHolder.append($newLinkLi);
// count the current form inputs we have (e.g. 2), use that as the new
// index when inserting a new item (e.g. 2)
$collectionHolder.data('index', $collectionHolder.find('input').length);
$addStepButton.on('click', function (e) {
// add a new tag form (see next code block)
addStepForm($collectionHolder, $newLinkLi);
jQuery('form').append($saveButton);
});
});
function addStepForm($collectionHolder, $newLinkLi) {
// Get the data-prototype explained earlier
var prototype = $collectionHolder.data('prototype');
// get the new index
var index = $collectionHolder.data('index');
var newForm = prototype;
// You need this only if you didn't set 'label' => false in your tags field in TaskType
// Replace '__name__label__' in the prototype's HTML to
// instead be a number based on how many items we have
// newForm = newForm.replace(/__name__label__/g, index);
// Replace '__name__' in the prototype's HTML to
// instead be a number based on how many items we have
newForm = newForm.replace(/__name__/g, index);
// increase the index with one for the next item
$collectionHolder.data('index', index + 1);
// Display the form in the page in an li, before the "Add a tag" link li
var $newFormLi = $('<div></div>').append(newForm);
// also add a remove button, just for this example
$newFormLi.prepend('<a href="#" class="remove-tag btn btn-outline-danger btn-sm float-right mb-1">X</a>');
$newLinkLi.before($newFormLi);
// handle the removal, just for this example
$('.remove-tag').click(function (e) {
e.preventDefault();
$(this).parent().remove();
return false;
});
}
</script>
{% endblock %}
类别类型.php
<?php
namespace App\Form;
use App\Entity\Category;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
class CategoryType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('title', TextType::class, [
'label' => 'Category Title:',
'attr' => [
'class' => 'form-control',
'placeholder' => 'Category Title'
]
])
->add('description', TextareaType::class, [
'label' => 'Category Description:',
'attr' => [
'class' => 'form-control',
'placeholder' => 'Category Description'
]
])
->add('save', SubmitType::class, [
'attr' => [
'class' => 'btn btn-primary btn-block'
]
])
;
}
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults([
'data_class' => Category::class,
]);
}
}
食谱类型.php
<?php
namespace App\Form;
use App\Entity\Recipe;
use App\Entity\Category;
use App\Form\StepType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
class RecipeType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('title', TextType::class, [
'attr' => [
'class' => 'form-control',
'placeholder' => 'Recipe Title'
]
])
->add('description', TextareaType::class, [
'attr' => [
'class' => 'form-control',
'placeholder' => 'Recipe Description'
]
])
->add('category', EntityType::class, [
'class' => Category::class,
'multiple' => true,
'mapped' => true,
'required' => false,
'attr' => [
'class' => 'form-control',
]
])
->add('steps', CollectionType::class, [
'label' => false,
'entry_type' => StepType::class,
'entry_options' => ['label' => false],
'allow_add' => true,
'by_reference' => false,
])
->add('save', SubmitType::class, [
'attr' => [
'id' => 'save',
'class' => 'btn btn-success btn-block'
]
])
;
}
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults([
'data_class' => Recipe::class,
]);
}
}
运行时错误引用来自 new.html.twig 的 {{ form_widget(form.category) }}(用于食谱)。
解决方案
我的怀疑是错误与控制器或路由器结合在一起。您确定在 Controller 操作中创建一个新类别,您正在渲染类别页面(类似于
return $this->render('category/new.html.twig');
而不是错误的食谱页面?所以它正在尝试查找form.category
,但该类别本身没有类别。
推荐阅读
- android - 模拟器无法在 MacO 上运行。模拟器声称操作系统已过时
- javascript - 如何在其他子菜单关闭时一次打开 1 个子菜单
- javascript - 如何在Javascript中分配具有相同属性的多个对象
- bash - `exec <&-` 有什么作用?
- d3.js - 为什么 phantomjs page.render 不捕获我的 D3 svg?
- r - 如何通过列表中的数据框名称联合大量数据框
- python - BeautifulSoup - 在这个 HTML 中查找链接
- java - 在移动到另一个片段并返回到它的同时保存片段内的 textView 值的正确方法是什么?
- gradle - 如何在 Gradle Kotlin DSL 中应用和配置 Kotlin No Arg 编译器插件?
- java - 对多对一关系的 API 请求