how to set sonata form data_class on edit - symfony

im stuck with following error message on a project with symfony 2.8 and sonata admin/media bundle. i log in sonata and navigate to the list view were i have an edit button. i click the edit button and get following error.
error message:
The form's view data is expected to be of type scalar, array or an instance of \ArrayAccess, but is an instance of class DateTime. You can avoid this error by setting the "data_class" option to "DateTime" or by adding a view transformer that transforms an instance of class DateTime to scalar, array or an instance of \ArrayAccess.
i found some answers via stackoverflow saying that the data_class needs to be set on the specific formtype. but thats sonata, were can i find the form i have to work on?

You can describe it in your admin class
protected function configureFormFields(FormMapper $form)
{
$form->add('date', 'datetime', array('data_class' => 'DateTime'));
}

Related

error when rendering Symfony 4 edit form that includes a File type

I'm following the steps outlined in this documentation https://symfony.com/doc/current/controller/upload_file.html to allow a file to be uploaded. It is working perfectly for adding a new item, but when I try to edit my entity, I'm getting the following error:
The form's view data is expected to be an instance of class Symfony\Component\HttpFoundation\File\File, but is a(n) string. You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms a(n) string to an instance of Symfony\Component\HttpFoundation\File\File.
I've tried code like what is suggested in that article to append the path of the folder as File type to the entity like this in my update method:
public function editAction(Request $request, Advertiser $advertiser)
{
$advertiser->setLogo(
new File($this->getParameter('logo_directory') .'/' . $advertiser->getLogo())
);
$editForm = $this->createForm(AdvertiserType::class, $advertiser);
$editForm->handleRequest($request);
if ($editForm->isSubmitted() && $editForm->isValid()) {
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('advertiser_list');
}
return $this->render('advertiser/index.html.twig', [
'form' => $editForm->createView()
]);
}
The logo_directory parameter is properly defined (and working fine for creating new entities).
Please let me know if you have any ideas what I am doing wrong.
Thanks for the help.
UPDATE: In this article The form's view data is expected to be an instance of class ... but is a(n) string there is a proposed solution to include in the form builder code the following:
->add('file', FileType::class, array('data_class' => null))
So I'm doing this now and the edit form will show - but it doesn't prepoulate with the previous selection.
->add('logo', FileType::class, array('data_class' => null), ['label' => 'Logo (JPG or PNG file)'])
Any thoughts on how this can be changed to allow the form to show with the previous selection pre-populated?
Setting a null data_class will remove the warning but it will not work, you don't need it at this point.
This is due to the fact that once your file is persisted, what remains in your database is just a path, not the file itself (which is on disk);
If you want to edit this entity again, the path (a string) must be converted to a File entity again; That's what the error message says.
.. and this is what you did when you wrote :
$advertiser->setLogo(
new File($this->getParameter('logo_directory') .'/' . $advertiser->getLogo())
);
Now, the problem that remains is that you want to prepopulate the file field. In fact, that is not possible, since the file field points to a location in your own computer, not to a file on your server (and you cannot automatically upload something from someone's computer like that, that would be very dangerous).
What you want to do is possibly indicate that a file is already stored, get its path and maybe display it to your user.
So in your Twig template, something like that (change with your real logo directory) :
{% if form.logo.vars.data %}
<img src="{{ asset('/uploads/logos_directory/' ~ form.logo.vars.data.filename) }}"/>
{% endif %}
Hope it's clear.

Give formbuilder class value as 'hidden'

I would like to give formBuilder User Entity as hidden value.
$form->add('user','hidden',array("data" => $user))
$user is User Entity.
However it shows this error.
Expected argument of type "Acme\UserBundle\Entity\User", "string" given
If I use 'null' instead of 'hidden'
$form->add('user',null,array("data" => $user))
it doesn't show the error and shows the select box of user Entity.
However I would like to use hidden.
How can I make it??
You did't specify the field type correctly - this is the correct way:
...
$formBuilder->add('user', HiddenType::class);
...
...
$form = $formBuilder->getForm();
$form->get('user')->setData($user->getId());
But you can't assign entity to the hidden field, so you can assign user's id for user identification.
Another option is to make data transformer and define own EntityHiddenType - more on this here: symfony : can't we have a hidden entity field?

A "__toString()" method was not found on the objects of type "Admin\UserBundle\Entity\Extension" passed to the choice field

I installed easyAdmin Bundle(symfony2) then :
I combined it with fosUserBundle.
I add an entity "extension".
So i created a user but when i tried to edit the account in the
dashboard i get this error :
A "__toString()" method was not found on the objects of type "Admin\UserBundle\Entity\Extension" passed to the choice field
So can anyone help me?
Sorry for the following question, but what about adding a __toString() method?
In your Extension:
public function __toString()
{
return $this->fieldYouWantToDisplayAsChoice;
}
For example, if your Extension has a property username, you can use return
$this->username, and the choice field will be populated with the username property of each user.
See magic __toString.

Symfony-Disabling specific field validations from controller

I am using Symfony 2.7.6. I have created an entity called employee and its interactive forms are generated using doctrine crud generator. Entity have the following fields
1. id
2. firstname
3. lastname
4. email
5. username
6. password
validations are working as expected from user registration form for all the fields.
ISSUE: I have created a login form and i want to suppress validation for the fields firstname, lastname and email and exclude these elements from rendering on my page
I have modified my controller like this for rendering my form
$entity = $em->getRepository('XXXEmployeeBundle:Employee');
$form = $this->createForm(new \XXX\EmployeeBundle\Form\EmployeeType(), $entity, array(
'action' => $this->generateUrl('user_login'),
'method' => 'POST',
));
$form->add('submit', 'submit', array('label' => 'Update'));
$form->remove('firstname');
$form->remove('lastname');
$form->remove('email');
$form->handleRequest($request);
This works fine when the from is rendering as the fields are excluded from the form. But my $form->isvalid() is returning false. As I have printed the errors using $form->getErrorsAsString() method, its showing like:
firstname: ERROR: First name cannot be empty. lastname: ERROR: Last name code cannot be empty. employeeFirstName: ERROR: Employee first name cannot be empty. email: ERROR: Email cannot be empty.
Is this the right method to achieve this functionality?? Please help me in solving the issue. Thanks
In your entity you mush include nullable=true like this
/**
* #ORM\Column(type="string", nullable=true)
*
* #var string
*/
protected $nombre;
And telling doctrine that is nullable, neither backend/frontend check the value.
Greetings !
I think problem in logic.
When you create registration form - you want to create and save new
entity.
When you create login form - you want to compare login and
password between form and entity.
So. You should create special form class for login (not from registration) and don't set data-enitity (second parameter in createForm function)
And, please check if you have the same form object in controller action that handles this form.
You can make a work around
Get all form's errors within your controller by
$form->getErrors()
and then loop over them, if it's the error you know it would happen, just bypass it on purpose and process further.
if ($form->isSubmitted()) { // remove $form->isValid() check
foreach($form->getErrors() as $error) {
// check if it's expected error, then do nothing and proceed further for user
// if it's unexpected throw an exception, catch them below and add error message to session flashbag. or something similar
}
}

How do you define the getter to use in a CRUD form besides defining __toString()?

If you've used Symfony2's generators to create CRUD forms from database entities, you may wind with an error like this on the "create new record" screen:
StringCastException: A "__toString()" method was not found on the objects of type
"ScrumBoard\ServiceBundle\Entity\Users" passed to the choice field. To read a
custom getter instead, set the option "property" to the desired property path.
If I'm reading this correctly, the problem is that it needs to display a dropdown list of users for the record I'm creating, but it doesn't know how to turn a "User" entity into a string.
Defining the __toString() method on my Users entity class fixes the problem. However, I can see right from the text of the error message that there is an alternative: read a customer getter instead, which is accomplished by "[setting] the option "property" to the desired property path."
This sounds like some kind of annotation. But in my searching, I can't figure out what that is. Because I want to have a thorough understanding of Symfony2--can someone help me out?
Thanks!
When creating an entity ( superclass of choice ) field type in a form. You need to specify which property shall be used for the labels/values otherwise the __toString() method of the underlying object will be used.
$builder->add('users', 'entity', array(
'class' => 'AcmeHelloBundle:User',
'property' => 'username',
));
Read more about it in the Form Type Reference for entity field Type.
Additional Info
A __toString() related error generally often comes from twig when generating a route in a template aswell.
if outputting an object an object in twig with {{ object }} ... twig will call the object'S __toString method.
This "trick" is used by the crud generated templates with SensioGeneratorBundle.
{{ path('article_show', {'id': article}) }}
with the route being something like this:
article_show:
pattern: /article/{id}
defaults: { _controller: AcmeArticleBundle:Article:show }
If you have the __toString method in your Article entity set to something like ...
public function __toString()
{
return $this->id;
}
... you dont't need to type
{{ path('article_show', {'id': article.id) }}
Generally Twig will automatically output Article::getId() if you use
{{ article.id }}
Hope this clarifies your findings.

Resources