Symfony, how show normal name of object not enetity number - symfony

I have problem with name of objects. In symfony 4, sonata admin.
When create field autocomplete with result from other enitity i got number of this object enitity, why i dont get normal name witch is saved in database ?
->add('child', ModelAutocompleteType::class, [
'property' => 'name',
'multiple' => 'true',
])
And there : Edite App\Entity\Invest..... want there normal name. Can anyone help ?

Try implementing "magic" method __toString() in you object class:
http://php.net/manual/en/language.oop5.magic.php#object.tostring
and inside it generate name of you object. So, add it like:
public function __toString()
{
return $this->foo;
}
Your function just has to return a string. Use variables you have in your object to generate that string.

Related

Symfony 5 / Easy Admin 3 - FormBuilder added field not displaying appropiate input

I am building a form using Easy Admin's FormBuilder. My goal is to have an AssociationField which represents a OneToMany relationship, for example, to assign multiple products to a shop. Additionally, I only want some filtered products to be listed, so I overrode the createEditFormBuilder method in the CrudController, I used this question as reference, and this is the code for the overridden function :
public function createEditFormBuilder(EntityDto $entityDto, KeyValueStore $formOptions, AdminContext $context): FormBuilderInterface
{
$formBuilder = parent::createEditFormBuilder($entityDto, $formOptions, $context);
$filteredProducts = $context->getEntity()->getInstance()->getFilteredProducts();
$formBuilder->add('products', EntityType::class, ['class' => 'App\Entity\Product', 'choices' => $filteredProducts, 'multiple' => true]);
return $formBuilder;
}
I expected an Association field as the ones configured in the configureFields() function, however, the displayed field doesn't allow text search or autocomplete features, plus has incorrect height.
Expected:
Actual:
I tried to change the second argument in the $formBuilder->Add() function, but all specific EasyAdmin types threw errors.
UPDATE: I also tried using EasyAdmin's CrudFormType instead of EntityType, which doesn't support the 'choice' parameter. Still, the result was the same.
There is setQueryBuilder on the field, you can use it for filtering entities like this
<?php
// ...
public function configureFields(string $pageName): iterable
{
// ...
yield new AssociationField::new('products')->setQueryBuilder(function($queryBuilder) {
$queryBuilder
->andWhere('entity.id IN (1,2,3)')
;
})
;
// ...
}

Symfony 5.2 error validations on field password. Why don't work NotBlank?

I am maintaining a large project. We recently updated the framework to version 5.2 and got an error:
Argument 1 passed to Symfony\Component\Security\Core\Encoder\MigratingPasswordEncoder::encodePassword() must be of the type string, null given, called in ...
This is how the buildForm() method looks like:
$builder
->setMethod('POST')
// ....
->add('pass', PasswordType::class, [
'label' => 'Password',
'constraints' => [new NotBlank(), new Length(['min' => 6, 'max' => 20])],
])
I can't figure out what the error is. Why don't work NotBlank? Something has changed in the framework, why does the code that used to work now throw an error?
Look at the configureOptions() method of your 'FormType' class. At data_class option you should have set an entity name.
In this entity you have to allow null value in the $pass property. Look at the $pass property type hint. It should be something like :
...
private ?string $pass = null;
...
That's because the form as to handle the data even though those could be invalid.
That's why most of the time you'll prefer to use a DTO (Data Transfer Object) in your data_class option for the FormType so you can have nullable properties.

Nested form: passing values

I'm a bit at a loss here with Symfony nested forms..
I have Events and RoleEntries i.e. the role that people or organizations can have for an event...
So I have an EventType form, with a nested RoleEntryType:
->addEventListener(FormEvents::PRE_SET_DATA,
function (FormEvent $event) {
$form = $event->getForm();
$data = $event->getData();
$form->add('roleEntries', 'collection', array(
'type' => new RoleEntryType($data),
'allow_add' => true,
'allow_delete' => true
));
}
)
the $data variable is caught by the RoleEntryType constructor:
$this->data=$data;
And I try to add a hidden field (since the user should not modify it, in the field):
->add($this->targetScope, 'hidden', array('data'=>$this->data))
At this point, Symfony is not happy because it cannot convert the $data to string
An exception has been thrown during the rendering of a template ("Catchable Fatal Error: Object of class IH\EventManagerBundle\Entity\Event could not be converted to string") in form_div_layout.html.twig at line 13.
so I try just to give it an Id
->add($this->targetScope, 'hidden', array('data'=>$this->data->getId()))
But it doesn't work either because a string is not enough, it wants a fully fledged event:
Catchable Fatal Error: Argument 1 passed to IH\EventManagerBundle\Entity\RoleEntry::setEvent() must be an instance of IH\EventManagerBundle\Entity\Event, string given, called in /Users/MTP/Documents/dev/MTP/vendor/symfony/symfony/src/Symfony/Component/PropertyAccess/PropertyAccessor.php on line 410 and defined
So I guess I'm doing it all wrong....
help!
$data contains the form data, so you need to extract your field value and pass it as value for your hidden field:
$form->add('targetScope', 'hidden', array('data' => $data['field_name']));
Without change your initial implantation, just add a __to string() magic method to Event entity and all should work as expected
Something like
Class Event
{
[...]
public function __toString()
{
return $this->name;
}
}
Of course $this->name; should be changed accordingly to your object properties.
If you need, when posting the form, to recreate (or take from db) an entity object, take a look to DataTransformers
Thanks for all your replies,
So using DataTransformer or creating a new field type (EntityHidden) both work... however, my problem stemed from something I forgot in my code which forced me to handle this in the FormType rather than in the entity...
Simply, there is no need to pass the primary key of the entity corresponding to the nesting form (Event) over to the nested form (RoleEntryType)... if I tell my Event entity setter that it should write a reference of the event in the new RoleEntry:
public function addRoleEntry(
{
$this->roleEntries[] = $roleEntry;
$roleEntry->setEvent($this);
return $this;
}
Sorry if my question wasn't clear and thanks for taking the time to answer!

How to use KNP Translatable in a form type

I'm using KNP Translatable and I have the following data structure:
User (id, name, email, password...)
Role (id, name #translatable)
User Role is a many to many relation.
I have the form type defined as this:
->add('roles', 'entity', [
'class' => 'SocialCarBackendBundle:Role',
'property' => 'name',
'multiple' => true,
'expanded' => true
])
And I implemented the __call method in the role entity:
public function __call($method, $arguments)
{
try {
return $this->proxyCurrentLocaleTranslation($method, $arguments);
} catch (\Symfony\Component\Debug\Exception\ContextErrorException $e) {
return $this->proxyCurrentLocaleTranslation('get' . ucfirst($method), $arguments);
}
}
Now, in the twig template I can call the name property of the roles without problems and it renders it correctly.
But when trying to render the form I get this error:
Neither the property "name" nor one of the methods "getName()",
"name()", "isName()", "hasName()", "__get()" exist and have public
access in class "SocialCar\BackendBundle\Entity\Role".
Is there any workaround for this? Thanks a lot
symfony's propertyaccessor component has not magic calls enabled for EntityType property
you can see vendor/symfony/symfony/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php to prove that.
so you have three ways(in order of complexity):
do getter and setters that call proxyCurrentLocaleTranslation, imho there are nothing bad using less magic things:)
use a more complex property like this
'property' => 'translations[' . $options['locale'] . '].name',
where $options['locale'] is the locale injected inside the form as an option
you can create a different EntityType class that extends your custom DoctrineType class that initializes PropertyAccessor to support magic calls
for more info about property accessor:
http://symfony.com/doc/current/components/property_access/introduction.html
and about the second way:
https://github.com/KnpLabs/DoctrineBehaviors/issues/67

Add custom validator on unmapped field, but with context of whole form submission?

tl;dr:
I need a custom validation constraint to run on an unmapped form field
I need the ID of the object the form is manipulating to eliminate it from consideration doing my validation constraint
Attaching the validation to the form itself or the unmapped field doesn't give me enough context to run my validation query
I have an unmapped field on my Person entity form that I need to run a validation on. I've followed this great article on how to do this, but my use case is slightly different and not entirely covered by the article.
I am making my own Unique Constraint that needs to run a custom query to determine the uniqueness. To run the query, I need access to the field value that was submitted, as well as the original Person object (so I can get it's ID if it's an update operation). Without also having the that Person object I won't be able to eliminate it from consideration during the uniqueness query.
If I apply the validator on the PersonType class like so:
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver
->setDefaults(array(
'data_class' => 'CS\AcmeBundle\Entity\Person',
'constraints' => array(
new MyUniqueValidator(),
)
))
;
}
Then the validator gets passed the entire Person object to perform the validation on. This doesn't help me, because the submitted form data is not persisted to the Person object (it's an unmapped field that I handle after $form->isValid() is called in the controller).
If I apply the validator to the unmapped field directly instead:
$builder
->add('myUnmappedField', 'text', array(
'mapped' => false,
'constraints' => array(
new MyUniqueValidator(),
)
),
))
Then the object I get passed to the validator is just the standalone form text, and nothing else. I don't have the ID Person object (if it was an update operation) to perform by uniqueness query.
Hopefully I've explained this properly. Do I have any options to do this sort of validation gracefully?
You say you have unmapped field. Would it help, if you make it mapped to the Person entity? Just make a new property in the Person class with getter and setter methods, but not to the ORM, since you don't want it persisted.
If you do not want to polute your Person class, you can also make another composite class, which will hold your currently unmapped field and a Person object (you will then make it mapped). Ofcourse you will then set data_class to match the new object's namespace.
Both above solutions should work with the upper code you have there. Please let me know it it helped.
You can achieve this by using a callback constraint with a closure.
To access your Person entity, you will need to add the field via an event listener.
$builder->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event) {
$form = $event->getForm();
$person = $event->getData();
$form->add('myUnmappedField', TextType::class, [
'mapped' => false,
'constraints' => [
new Symfony\Component\Validator\Constraints\Callback([
'callback' => function ($value, ExecutionContextInterface $context) use ($person) {
// Here you can use $person->getId()
// $value is the value of the unmapped field
}
])
],
]);
});

Resources