doctrine-orm - symfony2 - symfony 3.4 doctrine query
Incrustar un error de colección de formularios: no se pudo determinar el tipo de acceso para la propiedad (7)
Estoy intentando incrustar la colección de formularios de Tag
formulario de Service
, de acuerdo con este tutorial . Service
entidades de Tag
y Service
tienen una relación de muchos a muchos.
La forma se está procesando correctamente. Pero cuando envío el formulario, me sale
No se pudo determinar el tipo de acceso para la propiedad "tagList"
error. No entiendo por qué el nuevo objeto Tag
no se agrega a la clase de Service
llamando al método addTag()
.
Tipo de servicio
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(''title'', TextType::class, array(
''label'' => ''Title''
))
;
$builder->add(''tagList'', CollectionType::class, array(
''entry_type'' => TagType::class,
''allow_add'' => true,
''allow_delete'' => true,
''by_reference'' => false
)));
}
Clase de servicio
{
....
/**
* @ORM/ManyToMany(targetEntity="Tag", mappedBy="serviceList",cascade={"persist"})
*/
private $tagList;
/**
* @return ArrayCollection
*/
public function getTagList()
{
return $this->tagList;
}
/**
* @param Tag $tag
* @return Service
*/
public function addTag(Tag $tag)
{
if ($this->tagList->contains($tag) == false) {
$this->tagList->add($tag);
$tag->addService($this);
}
}
/**
* @param Tag $tag
* @return Service
*/
public function removeTag(Tag $tag)
{
if ($this->tagList->contains($tag)) {
$this->tagList->removeElement($tag);
$tag->removeService($this);
}
return $this;
}
}
Clase de etiqueta
{
/**
* @ORM/ManyToMany(targetEntity="Service", inversedBy="tagList")
* @ORM/JoinTable(name="tags_services")
*/
private $serviceList;
/**
* @param Service $service
* @return Tag
*/
public function addService(Service $service)
{
if ($this->serviceList->contains($service) == false) {
$this->serviceList->add($service);
$service->addTag($this);
}
return $this;
}
/**
* @param Service $service
* @return Tag
*/
public function removeService(Service $service)
{
if ($this->serviceList->contains($service)) {
$this->serviceList->removeElement($service);
$service->removeTag($this);
}
return $this;
}
}
Controlador de servicio
public function newAction(Request $request)
{
$service = new Service();
$form = $this->createForm(''AppBundle/Form/ServiceType'', $service);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($service);
$em->flush();
return $this->redirectToRoute(''service_show'', array(''id'' => $service->getId()));
}
return $this->render(''AppBundle:Service:new.html.twig'', array(
''service'' => $service,
''form'' => $form->createView(),
));
}
¿Podrías intentar implementar el código de esta URL?
Primero, intente cambiar los lados asignados / inversos y elimine $service->addTag($this);
de la Tag::addService
método Tag::addService
.
¿Tal vez se olvidó en __construct()
de la clase de servicio y la clase de etiqueta para inicializar $ tagList y $ serviceList así?
$this->tagList = new ArrayCollection();
$this->serviceList = new ArrayCollection();
Es una posibilidad remota, pero mirando sus anotaciones, creo que el problema podría estar relacionado con su relación manyToMany. Intente cambiar el lado propietario y el lado inverso (Intercambiar la relación) a menos que específicamente necesite actualizar desde ambos extremos (en ese caso, creo que la única solución es agregar los objetos manualmente o usar las relaciones oneToMany).
Los cambios realizados solo en el lado inverso de una asociación se ignoran. Asegúrate de actualizar ambos lados de una asociación bidireccional (o al menos el lado propietario, desde el punto de vista de Doctrine)
Este es un problema relacionado con la Doctrina que he sufrido anteriormente, consulte: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/unitofwork-associations.html
Esto parece un error con tu constructor. Prueba esto :
public function __construct()
{
$this-> tagList = new /Doctrine/Common/Collections/ArrayCollection();
}
Tal vez el problema es que Symfony no puede acceder a esa propiedad?
Si observa dónde se produce esa excepción (método writeProperty en la clase PropertyAccessor), dice que se puede lanzar:
Si la propiedad no existe o no es pública.
En el tutorial que mencionaste tiene propiedades $ tags, y el método addTag. Solo estoy adivinando aquí, pero tal vez hay una convención donde intenta llamar a los nombres de un método add($singularForm)
y esto está fallando porque la propiedad es tagList
y el método es addTag
.
No estoy 100% seguro, pero puedes intentar depurar estableciendo un punto de parada en ese método de Symfony para ver por qué se está lanzando.
Basado en Symfony 3.3.10
Realmente enfrenté este problema muchas y muchas veces, finalmente, una vez que descubrí de dónde venía este problema, dependiendo del nombre que le dé a la propiedad de su entidad, puede suceder que el sumador y el removedor de su propiedad de colección no sean exactamente lo que usted están esperando
Ejemplo: el nombre de la propiedad de su entidad es "foo" y usted esperaría que el sumador se llame "addFoo" y el removedor "removeFoo", pero de repente aparece el mensaje "No se pudo determinar el tipo de acceso para la propiedad" .
Así que empiezas a tener miedo al buscar problemas w / e en tu código, en vez de eso solo tienes que buscar este archivo dentro de los archivos principales de Symfony:
proveedor / symfony / symfony / src / Symfony / Component / PropertyAccess / PropertyAccessor.php
Dentro de este archivo hay un método llamado findAdderAndRemover . Vaya allí con su depurador y finalmente descubrirá que Symfony busca un nombre extraño para su agregador / removedor, que en realidad terminarán con "um" o "on" o "us" dependiendo del idioma (lenguaje humano) que usó para nómbralos. Ya que soy italiano esto sucede muy a menudo.
Tenga cuidado con eso, ya que la solución puede ser tan simple como cambiar el nombre utilizado para su método de agregar / eliminar dentro de su entidad para que coincidan con lo que el núcleo de Symfony está buscando.
Esto me sucede cuando uso la doctrina bin / console: generar: entidades para crear los métodos automáticamente para mí
Version corta:
Acabo de encontrarme con este problema y lo resolví agregando un setter para la propiedad afectada:
No se pudo determinar el tipo de acceso para la propiedad "tagList"
public function setTagList(Array $tagList)
{
$this->tagList = $tagList;
}
Versión larga:
El mensaje de error indica que Symfony está intentando modificar el estado del objeto, pero no puede averiguar cómo realizar el cambio debido a la forma en que está configurada su clase.
Echando un vistazo a las partes internas de Symfony , podemos ver que Symfony le brinda 5 oportunidades para darle acceso y elige la mejor en este orden de arriba a abajo:
- Un método de establecimiento llamado
setProperty()
con un argumento:
Esto es lo primero que Symfony comprueba y es la forma más explícita de lograrlo. Por lo que yo sé, esta es la mejor práctica:
class Entity {
protected $tagList;
//...
public function getTagList()
{
return $this->tagList;
}
//...
}
- Un combinador y definidor en un método con un argumento:
Es importante darse cuenta de que Symfony también tendrá acceso a este método para obtener el estado del objeto. Como esas llamadas de método no incluyen un argumento, el argumento de este método debe ser opcional.
class Entity {
protected $tagList;
//...
public function tagList($tags = null)
{
if($reps){
$this->tagList = $tags;
} else {
return $this->tagList;
}
}
//...
}
La propiedad afectada se declara como pública:
class Entity { public $tagList; //... other properties here }
Un método mágico
__set
:
Esto afectará todas las propiedades en lugar de solo la que usted deseaba.
class Entity {
public $tagList;
//...
public function __set($name, $value){
$this->$name = $value;
}
//...
}
- Un método mágico
__call
(en algunos casos):
No pude confirmar esto, pero el código interno sugiere que esto es posible cuando la magic
está habilitada en la construcción de PropertyAccessor.
Sólo se requiere el uso de una de las estrategias anteriores.