I'm getting the following exception when trying to update an entity:
The form's view data is expected to be of type scalar, array or an instance of \ArrayAccess, but is an instance of class Proxies__CG__\Acme\DemoBundle\Entity\TicketCategory. You can avoid this error by setting the "data_class" option to "Proxies__CG__\Acme\DemoBundle\Entity\TicketCategory" or by adding a view transformer that transforms an instance of class Proxies__CG__\Acme\DemoBundle\Entity\TicketCategory to scalar, array or an instance of \ArrayAccess.
When creating, no problem occurs and the relationship is OK. However, when updating, this strange exception comes up. My entities are setup like this:
class Ticket
{
// ...
/**
* #var TicketCategory
*
* #ORM\ManyToOne(targetEntity="TicketCategory")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
protected $category;
// ...
}
class TicketCategory
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string $title
*
* #ORM\Column(name="title", type="string", length=255)
* #Assert\NotBlank()
*/
private $title;
// ...
}
Form
class TicketType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', 'text', array(
'error_bubbling' => true,
)
)
->add('category', 'text', array(
'error_bubbling' => true,
)
)
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\DemoBundle\Entity\Ticket',
'csrf_protection' => false,
));
}
public function getName()
{
return '';
}
}
Any ideas, guys?
Problem is:
$builder
->add('category', 'text', array(
'error_bubbling' => true,
)
)
;
Field category is declared of type "text", thus you can pass only scalars (string, bool, etc) to it. That is you can only specify properties (of Ticket class) that are scalars.
In Ticket class category it's an entity, so the error occurs.
Without knowing what you want to accomplish, i guess you want to make the user choose a category for the ticket, so i'll do:
$builder
->add('category', 'entity', array(
'label' => 'Assign a category',
'class' => 'Acme\HelloBundle\Entity\TicketCategory',
'property' => 'title',
'multiple' => false
)
)
;
More on entity field type.
EDIT: don't know if you omitted it, but Ticket has no property named "title".
Related
I am currently using doctrine wrong as when I have a choiceType in my entity, I use this:
/**
* #ORM\Column(type="integer")
*/
private $type;
plus in my builder:
->add('type', ChoiceType::class, ['choices' => ['Pattern' => 0, 'Image' => 1]])
I would like now to have something cleaner and have another entity in my database that would be linked to this main entity. Here is what I did.
Created a "category" entity (and created in DB):
/**
* #ORM\Entity(repositoryClass="App\Repository\CategoryRepository")
* #ORM\Table(name="vipbox_mep_category")
*/
class Category {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $category;
/**
* #return mixed
*/
public function getCategory()
{
return $this->category;
}
/**
* #param mixed $category
*/
public function setCategory($category): void
{
$this->category = $category;
}
}
linked my main entity to the second one (with the getter and setter):
/**
* #ORM\OneToOne(targetEntity="App\Entity\Category")
*/
private $category;
Added my category to my form:
->add('category', CategoryType::class, ['required' => true, 'label' => 'Category'])
Extended AbstractType form for my category:
class CategoryType extends AbstractType
{
/**
* #var RouterInterface $route
*/
private $router;
/**
* #param RouterInterface $router
*/
public function __construct(RouterInterface $router)
{
$this->router = $router;
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'required' => true,
'label' => 'Category'
]);
}
/**
* {#inheritdoc}
*/
public function getParent()
{
return ChoiceType::class;
}
}
Populated my Category table with text sample data (2 rows)
Tested to show my form, I does compute, but I have an empty choiceType:
I know I missed one/multiple things on my way, any clues ?
Assuming you have saved some data in your Category table to populate your drop-down list just change your step 3 from this:
->add('category', CategoryType::class, ['required' => true, 'label' => 'Category'])
to this:
->add('category', EntityType::class, [
'class' => Category::class,
'required' => true,
'label' => 'Category',
])
There are lots of other options available for EntityType, see the docs.
I have three entities running in Symfony:
Professional
class Professional extends User
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\OneToMany(targetEntity="TurnsProfessional", mappedBy="professional")
*/
private $turns;
}
Turn
class Turn
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\OneToMany(targetEntity="TurnsProfessional", mappedBy="turn")
*/
private $professionals;
}
TurnsProfessionals
class TurnsProfessional
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="Turn", inversedBy="professionals")
* #ORM\JoinColumn(name="turn_id", referencedColumnName="id")
*/
private $turn;
/**
* #ORM\ManyToOne(targetEntity="Professional", inversedBy="turns")
* #ORM\JoinColumn(name="professional_id", referencedColumnName="id")
*/
private $professional;
/**
* #ORM\Column(type="boolean")
*/
private $status;
}
In the FormType I have this:
->add('turns', 'entity',
array('class' => 'AppBundle:TurnsProfessional',
'property' => 'label',
'multiple' => true,
'expanded' => true,
));
What I would like to do is load all the "turns" available in "Turn" entity (Monday morning, Monday evening, Tuesday morning, etc.) and show them like checkboxes in a form. If the turn is checked, the turn will be registered in TurnsProfessional with status = 1 and if not with status = 0.
When I have all the turns saved in TurnsProfessional with status = 0 or status = 1, Symfony print all the options right and everything works. But, the first time no turn are created for the professional so the add('turns') method returns an empty value with no checkboxes.
How could I show all the options available in Turn entity in this case?
Thanks!
UPDATE FormType
I've tried to add a query_builder option in the FormType:
->add('turns', EntityType::class,
array('class' => 'AppBundle:Turn',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('turn')
->orderBy('turn.id', 'ASC');
},
'choice_label' => 'label',
'multiple'=>true,
'expanded'=>true,
))
Now, the form shows all the options but when I try to save the form I get the following error:
Found entity of type AppBundle\Entity\Turn on association
AppBundle\Entity\Professional#turns, but expecting
AppBundle\Entity\TurnsProfessional
You have an error because your entity is waiting for a TurnsProfessional object and you are trying to give it a Turn object. To solve this you should not map directly the field to your entity:
->add('turns', EntityType::class,
array('class' => 'AppBundle:Turn',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('turn')
->orderBy('turn.id', 'ASC');
},
'choice_label' => 'label',
'multiple' => true,
'expanded' => true,
'mapped' => false
))
Then in your controller you can access to the result like this:
$turns = $form->get('turns);
But you have to keep in mind that $turns will only contains the Turn entities you selected in your form.
I have 2 entities: Accounts and Patients:
class Patients
{
//..
/**
* #var Accounts
*
* #ORM\OneToOne(targetEntity="Accounts", mappedBy="patients")
* #Assert\Valid()
*/
private $accounts;
// ..
}
class Accounts {
// ...
/**
* #var Patients
*
* #ORM\OneToOne(targetEntity="Patients", inversedBy="accounts")
* #ORM\JoinColumn(name="patients_id", referencedColumnName="id")
*
*/
private $patients;
/**
* #var string
*
* #ORM\Column(name="email", type="string", length=100, nullable=true, unique=true)
* #Assert\NotBlank(groups={"emailValidation"})
* #Assert\Email(groups={"emailValidation"})
*
*/
private $email;
/// ...
}
I need to build a form with patients info (firstname, lastname, email) and validate it.
I did it like this:
class PatientsType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
// .....
->add('email', EmailType::class, array(
'mapped' => $options['formState'] == 'display' ? false : true,
'property_path' => 'accounts.email',
'data' => $options['email']
))
}
//....
$resolver->setDefaults(
array(
'formState' => 'display',
//...
}
The
'mapped' => $options['formState'] == 'display' ? false : true,
Is an ugly workaround that I had to make because, without that I had two situations:
1.
->add('email', EmailType::class, array(
'property_path' => 'accounts.email',
'data' => $options['email']
))
Will give the following error:
PropertyAccessor requires a graph of objects or arrays to operate on,
but it found type "NULL" while trying to traverse path
"accounts.email" at property "email".
->add('email', EmailType::class, array(
'mapped' => false,
'property_path' => 'accounts.email',
'data' => $options['email']
))
Is not taking into account the validation groups inside entities..
Is there an elegant way to validate the email inside the accounts entity?
I have many to many association in my entity and i would like to use the collection type field from symfony to add multiple times.
I've never done this way before and i'm kinda lost.
The field that i would like to have multiple times is headquarter with a non mapped field for each headquarter.
The error that i'm getting;
The property "headquarter" in class "AppBundle\Entity\SurveyManager"
can be defined with the methods "addHeadquarter()",
"removeHeadquarter()" but the new value must be an array or an
instance of \Traversable, "AppBundle\Entity\HeadQuarterManager" given.
The Form Type implementing the Collection.
class SurveyOptionType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('headquarter', CollectionType::class, [
'entry_type' => HeadQuarterType::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'label' => 'Sediu',
])
->add('isEnabled', CheckboxType::class, [
'label' => 'Chestionar Activ',
'required' => false,
])
->add('submit', SubmitType::class, [
'label' => 'Salveaza',
]);
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => SurveyManager::class
]);
}
}
This is the Collection Form
class HeadQuarterType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('headquarter', EntityType::class, [
'class' => HeadQuarterManager::class,
'label' => 'Sediu',
])
->add('userNumber', TextType::class, [
'label' => 'Numar Utilizatori',
'mapped' => false,
])
;
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => SurveyManager::class
]);
}
}
UPDATE:
Here is the Entity class stripped away from all the uncesessary data
class SurveyManager
{
/**
* #var int
*
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\HeadQuarterManager")
* #ORM\JoinTable(name="survey_headquarters",
* joinColumns={#ORM\JoinColumn(name="survey_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="headquarter_id", referencedColumnName="id")}
* )
*/
private $headquarter;
public function __toString()
{
// TODO: Implement __toString() method.
return $this->name;
}
/**
* Constructor
*/
public function __construct()
{
$this->question = new \Doctrine\Common\Collections\ArrayCollection();
$this->headquarter = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add headquarter
*
* #param \AppBundle\Entity\HeadQuarterManager $headquarter
*
* #return SurveyManager
*/
public function addHeadquarter(\AppBundle\Entity\HeadQuarterManager $headquarter)
{
$this->headquarter[] = $headquarter;
return $this;
}
/**
* Remove headquarter
*
* #param \AppBundle\Entity\HeadQuarterManager $headquarter
*/
public function removeHeadquarter(\AppBundle\Entity\HeadQuarterManager $headquarter)
{
$this->headquarter->removeElement($headquarter);
}
/**
* Get headquarter
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getHeadquarter()
{
return $this->headquarter;
}
}
Controller method
$em = $this->getDoctrine()->getManager();
$surveyRepository = $em->getRepository(SurveyManager::class);
//$surveyManager = $surveyRepository->findOneById($surveyId);
$surveyManager = new SurveyManager();
$form = $this->createForm(SurveyOptionType::class, $surveyManager);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($surveyManager);
$em->flush();
return $this->redirectToRoute('admin_survey-manager_survey_options',
[
'id' => $surveyManager->getId()
]);
}
return [
'surveyManager' => $surveyManager,
'form' => $form->createView(),
];
While doing research about this i did a separate demo to test on it to see better the problem.
Here is an updated code simplified that should work really smooth
https://gist.github.com/bogdaniel/a0bcc848e2bd282382f45a2bd15cc0e2
You will find more info about the error in the gist.
I don't really understand what do you want to archive, and what exactly does it mean:
The field that i would like to have multiple times is headquarter with a non mapped field for each headquarter.
But the error is quite self-explaining. Your SurveyManager class has to have some methods to populate data from Form. The flow is following - Form gets data (from User, for example) with an array of headquarters. And then Form looks for the way to pass this array to the object - and doesn't find them because you don't have appropriate methods.
Id doesn't matter if the property is mapped (I believe, you mean mapped to Doctrine), it still has be provided a way to pass data from Form to Object.
How are you rendering your form? I suspect something similar to the issue found here: Error : the new value must be an array or an instance of \Traversable, Entity class given
Other than that, the only issue I can see in your code is that the 'data_class' option from HeadQuarterType should be HeadQuarterManager::class.
This is code is work fine when I am creating a category, when we create a subcategory it gives error.
In Entity file:
/**
* Music\Bundles\Core\Entity\MusicCategory
* #ORM\Table(name="ms_musiccategory")
* #ORM\Entity()
* #ORM\Entity(repositoryClass="Music\Bundles\Core\Entity\Repository\CategoryRepository")
* #UniqueEntity(fields={"name"},message="The name is already in this system.")
*/
class MusicCategory
{
/**
* #ORM\Column(name="id",type="integer")
* #ORM\Id()
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
*#ORM\ManyToOne(targetEntity="MusicCategory")
*#ORM\JoinColumn(name="parent_Id", referencedColumnName="id")
*
*/
private $parentid;
In Formbuilder:
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('name')
->add('description')
->add('parentid', 'entity', array('class'=>'MusicCoreBundle:MusicCategory',
'property' => 'name',
'required' => false,
'query_builder' => function(EntityRepository $er) {return $er->createQueryBuilder('s')->orderBy('s.name', 'ASC');},
'empty_value' => 'No category'
));
}
Change into Entity file:
/**
* #ORM\Column(name="id",type="integer")
* #ORM\Id()
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="MusicCategory", mappedBy="parent")
*/
protected $children;
/**
* #ORM\ManyToOne(targetEntity="MusicCategory", inversedBy="children")
* #ORM\JoinColumn(name="parent_id", referencedColumnName="id")
*/
protected $parent;
public function __construct()
{
$this->parentId = null; // Default value for column parent_id
$this->children = new \Doctrine\Common\Collections\ArrayCollection();
}
Change into formbuilder also:
->add('parentid', 'entity', array('class'=>'MusicCoreBundle:MusicCategory',
'property' => 'name',
'required' => false,
'query_builder' => function(EntityRepository $er) {return $er->createQueryBuilder('s')->orderBy('s.name', 'ASC');},//->where('s.parentid is NULL')
'empty_value' => 'No category',
));
Use this code.feel free to enjoy. :)
You are probably doing something like
$category->setParent($parentId);
where you should do
$category->setParent($parent);
where $parent is an object of type 'MusicCategory'
Doctrine works with entities, not id(s)
also take a look at
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html
mainly the parts about self-referencing associations.
I think its a association mapping problem...
You should check the association...