How to add non-persistent field to form? - symfony

There is SonataAdminBundle and User entity. Admin service for it:
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('name')
// ...
->add('send_greeting', 'checkbox')
;
}
Field send_greeting is not related to User entity. It required only for admin service (depends it value we would send email or not after saving user). So how it possible add this field to form without binding to entity?

With symfony 2.1 and above, use mapped instead of property_path. (Symfony2 form reference)

You can set property_path option to false. e.g
->add('send_greeting', 'checkbox',array(
'property_path' => false
))
...

Related

SonataAdmin create entity with boolean field

I have this entity, if I create a record like this.
$synopsis = new Synopsis();
$synopsis->setPartOne("a");
$synopsis->setPartTwo("b");
$synopsis->setTitle("A");
$synopsis->setSubtitle("B");
$synopsis->setEnabled(false);
$em->persist($synopsis);
$em->flush();
And then I go to my Admin, I see the enabled field to "no" which is expected.
But now, If I use the sonata admin new form field, even if I choose enabled "no", the record is created with enabled = true. And I don't really see why it would be like that.
Here is what I have in my SynopsisAdmin
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper->add('title', TextType::class);
$formMapper->add('subtitle', TextType::class);
$formMapper->add('partOne', TextAreaType::class);
$formMapper->add('partTwo', TextAreaType::class);
$formMapper->add('enabled', BooleanType::class);
}
This is how the enabled field is defined in the entity
/**
* #ORM\Column(type="boolean")
*/
private $enabled;
Thanks for your help.
EDIT: Fun facts too, even if I see no in the sonata view list, when I go to the form view, I see yes instead.
I suspect an error within the sonata core functionnality.
I think you should use the CheckboxType instead of the BooleanType for your Form fields.
Looks like the BooleanType is ment for the list, show and grid actions.
https://symfony.com/doc/master/bundles/SonataAdminBundle/reference/field_types.html
Update
To use the BooleanType you have to set the 'transform' option to true.
This transforms your boolean value to the YES/NO options in the BooleanType:
$formMapper
->add('enabled', BooleanType::class, [
'transform' => true
])

Send a custom email from sonata admin using variables

I have a list view in sonata admin. I want to add a column that will allow me to click on a link to send an email. The link action will know variables from that row in the table so that it can fill in the email. I was able to add the column and can visualize a twig template. I've added the following function to the Admin Class:
public function sendEmail( \Swift_Mailer $mailer)
{
$message = (new \Swift_Message('some email'))
->setFrom('contact#example.com')
->setTo('contact#example.com')
->setBody(
$this->renderView(
'emails/response.html.twig',
array('manufacturer' => $manuvalue, 'modelnum' => $modelnumvalue, 'email' => $email)
),
'text/html');
$mailer->send($message);
}
I'm stuck on how to connect these pieces together so that when I click on the link the email is sent and includes the params from the row. I have email working on form submit in other areas of the site, but need help figuring out the way to do this manually.
As you mentioned in the comments, what you want to do is typically a Custom Action
In order to ensure that this action can not be accessed via direct request and can only be performed by admin, you could do use a template like this for your customAction :
...
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
...
//AuthorizationCheckerInterface injected as authorizationChecker
public function customAction($id){
$object = $this->admin->getSubject();
if (!$object) {
throw new NotFoundHttpException(sprintf('unable to find the object with id: %s', $id));
}
// Check access with role of your choice
$access = $this->authorizationChecker->isGranted('ROLE_ADMIN');
if($access){
//Do your action
} else {
throw $this->createAccessDeniedException("You don't have the rights to do that!");
}
}
I ended up doing a custom route and protected it with security settings that #dirk mentioned.

What does the constraint Required do?

What does the constraint Required do in the form builder? If a field was not submitted (not empty value!), I don't receive a corresponding error message. This field is just ignored.
$builder
->add('firstname', TextType::class, [ 'constraints' => [new NotBlank()], 'required'=>true])
->add('lastname', TextType::class, [ 'constraints' => [new NotBlank(),] ,'required'=>true])
How can say, that the field always MUST be submitted?
Thank you.
Required mean your field need a value tu be be submitted. It's similar to the HTML behaviour.
EDIT:
https://symfony.com/doc/current/reference/forms/types/form.html#constraints
https://symfony.com/doc/current/form/without_class.html#form-option-constraints
The issue is on your constraints, I don't know for sure but if adding those to your form don't fix your problem, have a look att adding assert to your Entity attached to your form
https://symfony.com/doc/current/reference/constraints/NotBlank.html
Then validate this entity in your controller
https://symfony.com/doc/current/validation.html
And relying on this you might add errors to the form.
A colleague has found the solution:
In the related entity, you need to define a callback-function like this:
/**
* Check bank account by "CUSTOMER" - not null
* Because NotNull() not working in form type!
* #Assert\Callback()
*/
public function validateBankaccount(ExecutionContextInterface $context)
{
if ($this->type == self::TYPE_CUSTOMER && is_null($this->bankAccount)) {
$context->buildViolation('Bank account is required!')
->atPath('bankAccount')
->addViolation();
}
}

Sonata Admin Bundle: for create new, how can I have user already selected?

I have two (2) Admins, UserAdmin and CarAdmin. From the list view of UserAdmin, I want to have a custom action that redirects to CarAdmin create view with the user already selected.
So far I have managed to create a custom action with its controller. My challenge is to redirect to CarAdmin create/new form passing some parameters for data persistence.
Any points of reference will be much appreciated.
Thanks
Sonata Admin allows to resolve such task pretty easy, no need to make a custom action. One of the solutions could be:
Define a custom template for one column in UserAdmin list view, render a special button(link) in it. A link should lead to CarAdmin create action with some get parameter.
In CarAdmin in method getNewInstance() check that if there is a special get parameter - set user with that ID. This step can also be done in methods getFormFields(), prePersist(), etc.
Some code samples:
In UserAdmin
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->add('actions', 'string', array(
'template' => 'your_template_name.html.twig',
'mapped' => false,
)
);
}
In your_template_name.html.twig
Create Car for this user
In CarAdmin
public function getNewInstance()
{
$car= parent::getNewInstance();
$userId = $this->getRequest()->query->get('user');
if ($userId) {
$em = $this->modelManager->getEntityManager(User::class);
$user = $em->getRepository(User::class)->find($id);
$car->setUser($user);
}
return $car;
}

What's a good way to create an "agree to terms" checkbox in Symfony2?

I have a form that has an "I have read and agree to the terms of service" checkbox on it. The box must be checked in order for the form to be considered valid, but there's no reason to save that value to the database, of course, and there's no reason to add an attribute to the Entity.
What's a good way to implement this kind of functionality in Symfony2 such that the form won't be considered valid unless the box is checked?
This question is quite old and Symfony has updated this a lot. For Symfony 3.x you can do something like:
$builder->add('terms', CheckboxType::class, [
'mapped' => false,
'constraints' => new IsTrue(),
]);
From symfony docs:
When mapping forms to objects, all fields are mapped. Any fields on the form that do not exist on the mapped object will cause an exception to be thrown.
In cases where you need extra fields in the form (for example: a "do you agree with these terms" checkbox) that will not be mapped to the underlying object, you need to set the property_path option to false:
use Symfony\Component\Form\FormBuilderInterface;
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('task');
$builder->add('dueDate', null, array('property_path' => false));
}
The field data can be accessed in a controller with:
$form->get('dueDate')->getData();

Resources