SonataAdmin hooks are not firing - symfony

I have Symfony 2.8. I use SonataAdminBundle v2.3 + a2lix/TranslationFormBundle v2.1 + SonataMediaBundle v2.3. I have NewsAdmin class:
class NewsAdmin extends Admin
{
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('translations', 'a2lix_translations', ['fields' => [
'content' => [
'field_type' => 'ckeditor',
]
]])
->add('excerptImage', 'sonata_type_model_list', [], [
'link_parameters' => ['context' => 'default'],
'require' => false
])
->add('excerptImageSide')
->add('category', 'sonata_type_model', [
'class' => 'AppBundle\Entity\NewsCategory',
'property' => 'shortName'
])
;
}
// configureDatagridFilters(), configureListFields() ...
// Does not firing!
public function postUpdate($news)
{
dump('preUpdate');
}
// Does not firing!
public function prePersist($news)
{
dump('prePersist');
}
}
The problem is that nor postUpdate, nor prePersist methods are not firing, so I don't see in web profiler string 'preUpdate' or 'prePersist'. Why that happens? And how to fix that?
P.S. Please, let me know if you need more information.

Just add a die and you'll see your dump.
public function prePersist($news)
{
dump('prePersist');
die;
}
EDIT
That's because the dump is not called directly from the controller action that renders the view, nor from a method called by the action, but in an EventListener that is totally standalone.

Related

Symfony Form - Custom Button Type can't read property

I'm working with Symfony Form in Symfony 5.4 and I need the following:
I have a DTO with some properties. In our application, the default ButtonType has some special handling in the theme-twig (special container with special classes around the button).
Now I need another custom Button-Type to give this new tyoe his own special theme-handling.
I have built the following code for this:
Custom ButtonType-Class:
class FormAddButtonType extends AbstractType
{
public const BLOCK_PREFIX = 'formaddbutton';
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'attr' => [
'class' => 'button blue-button',
],
]);
}
public function getBlockPrefix(): string
{
return self::BLOCK_PREFIX;
}
public function getParent(): string
{
return ButtonType::class;
}
}
Now I add two buttons to my form:
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('test_button_1', ButtonType::class, [
'label' => 'Test Button 1',
'attr' => [
'class' => 'button blue-button',
],
'row_attr' => ['class' => 'noborder'],
]);
$builder->add('test_button_2', FormButtonType::class, [
'label' => 'Test Button 2',
'attr' => [
'class' => 'button blue-button',
],
'row_attr' => ['class' => 'noborder'],
]);
}
The first Button will be rendered without any problem. But the second button (my custom button type) will cause the following error:
Can't get a way to read the property "test_button_2" in class "My\Name\Space\Dto\MyDataDto".
Yeah, this class / object doesn't have a property called "test_button_2". But "test_button_1" doesn't exist either and this button works just fine. Manually setting "'mapped' => false" doesn't work either.
If I add my FormAddButtonType inside of my custom Collection Type via POST_SET_DATA-listener, there is no problem. But if I try to use it in the "main form", it won't work.
Can you tell me what I'm doing wrong?
add
"mapped" => false
in the field option, it stands for "this field doesn't exist in the entity".
I think it does work with the default ButtonType as they probably set it on the
$resolver->setDefaults([ /* ... */ ]);
method
doc: https://symfony.com/doc/current/reference/forms/types/form.html#mapped

Sonata admin send model_manager to custom field ModelAutocompleteType

Hello i am using symfony 5.4 with sonata admin. I created custom AppModelAutocopleteType
class AppModelAutocompleteType extends AbstractType
{
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'callback' => static function (AdminInterface $admin, array $property, $value) {
AutocompleteForIntegerAndString::execute($admin, $property, $value);
},
'to_string_callback' => function($entity, $property) {
return $entity->getLabel();
},
'minimum_input_length' => 1,
'delay' => 333,
]);
}
public function getParent()
{
return ModelAutocompleteType::class;
}
}
and in sonata admin class (Lead entity) in filter section i add this (networkProvider is relation to Lead entity)
->add('networkProvider', ModelFilter::class, [
'field_type' => AppModelAutocompleteType::class,
'field_options' => [
'property' => ['code', 'name'],
'class' => Lead::class,
'model_manager' => $this->getModelManager(),
],
])
thing is when i enable in frontend my filter it shows up correctly and when i type something i get error. In profiler (ajax request) i can see this problem
Could not find admin for code "".
Based on what i tried it looks like maybe something wrong with model_manager, i don't know if i sent it properly.
Any help how can i create custom ModelAutocompleteType which will work with sonata admin is really appreciate.

OroPlatform: Override core entity form builder

Context
I'm trying to change the form type of one field on one of the core entity: Business Unit
The default form field is TextField and I want to change it to ChoiceType.
Here is my custom field on Business Unit entity created with migration :
$table->addColumn('periodicite', 'string', [
'oro_options' => [
'extend' => ['owner' => ExtendScope::OWNER_CUSTOM],
'entity' => ['label' => 'Périodicité'],
],
]);
Issue
I've seen on the Oro documentation that entity_config.yml could solve my problem. I've tried to put these lines but it doesn't work :
entity_config:
business_unit:
entity:
items:
periodicite:
form:
type: Symfony\Component\Form\Extension\Core\Type\ChoiceType
options:
choices:
Mensuel: Mensuel
Trimestriel: Trimestriel
placeholder: false
required: true
label: "Périodicite"
I have also tried to create a new migration to change the field type on my custom field but it doesn't work
<?php
namespace Baltimore\Bundle\AppBundle\Migrations\Schema\v1_1;
use Doctrine\DBAL\Schema\Schema;
use Oro\Bundle\EntityConfigBundle\Migration\UpdateEntityConfigFieldValueQuery;
use Oro\Bundle\EntityExtendBundle\EntityConfig\ExtendScope;
use Oro\Bundle\EntityExtendBundle\Migration\Extension\ExtendExtension;
use Oro\Bundle\EntityExtendBundle\Migration\Extension\ExtendExtensionAwareInterface;
use Oro\Bundle\MigrationBundle\Migration\Migration;
use Oro\Bundle\MigrationBundle\Migration\QueryBag;
use Oro\Bundle\OrganizationBundle\Entity\BusinessUnit;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
class UpdateBusinessUnitField implements Migration, ExtendExtensionAwareInterface
{
/** #var ExtendExtension */
protected $extendExtension;
/**
* #inheritdoc
*/
public function setExtendExtension(ExtendExtension $extendExtension)
{
$this->extendExtension = $extendExtension;
}
public function up(Schema $schema, QueryBag $queries)
{
$queries->addQuery(
new UpdateEntityConfigFieldValueQuery(
BusinessUnit::class,
'periodicite',
'form',
'form_type',
ChoiceType::class
)
);
$queries->addQuery(
new UpdateEntityConfigFieldValueQuery(
BusinessUnit::class,
'periodicite',
'form',
'form_options',
[
'choices' => [
'Mensuel' => 'Mensuel',
'Trimestriel' => 'Trimestriel',
'Annuel' => 'Annuel',
],
]
)
);
}
}
I have found a solution with the changeColumn method in my migration file and it works like a charm.
By the way, these properties works also with the addColumn method.
public function up(Schema $schema, QueryBag $queries)
{
$table = $schema->getTable('oro_business_unit');
$table->changeColumn('periodicite', [
'oro_options' => [
'extend' => ['owner' => ExtendScope::OWNER_CUSTOM],
'entity' => ['label' => 'Périodicité'],
'form' => [
'form_type' => ChoiceType::class,
'form_options' => [
'choices' => [
'Mensuel' => 'Mensuel',
'Trimestriel' => 'Trimestriel',
'Semestriel' => 'Semestriel',
'Annuel' => 'Annuel'
]
]
],
],
]);
}
I don't know about the possibility to override entity config metadata using the YAML file. If there is - please share the documentation you used to implement it in the comments.
But for sure, you can manage the same using the schema migration, like in this example:
class UpdateOpportunityRelationFormType implements Migration
{
/**
* {#inheritdoc}
*/
public function up(Schema $schema, QueryBag $queries)
{
$queries->addQuery(
new UpdateEntityConfigFieldValueQuery(
Quote::class,
'opportunity',
'form',
'form_type',
OpportunitySelectType::class
)
);
$queries->addQuery(
new UpdateEntityConfigFieldValueQuery(
Quote::class,
'opportunity',
'form',
'form_options',
['attr' => ['readonly' => true]]
)
);
}
}

custom form to accept only specific email address FOSUserBundle 2.0/ Symfony3

I try to learn to create a website with Symfony 3.1.10. To help me on my project to create login/register, i decided to use the bundle "FOSUserBundle 2.0". So for now i create a Custom form (i changed the username field by name field). For my project, i tried to allow to register only user with a specific email address. So after few research, they explain to create custom behaviour, FOSUserbundle created Events. So when i have i REGISTRATION_SUCCESS, i create custom event listener as you can see below.
class CheckEmailBefore implements EventSubscriberInterface {
private $router;
private $request;
public function __construct(RouterInterface $router,Request $request)
{
$this->router = $router;
$this->request = $request;
}
public static function getSubscribedEvents() {
return [
FOSUserEvents::REGISTRATION_SUCCESS => 'onCheck'
];
}
/**
* #param FormEvent $event
*
*/
public function onCheck(FormEvent $event){
$user = $event->getForm()->getData();
$email = $user->getEmailCanonical();
$format = explode("#",$email);
if((strcmp($format[1] , "truc.com")===0) || (strcmp($format[1] , "chose.com") === 0)){
$url = $this->router->generate('list');
$response = new RedirectResponse($url);
$event->setResponse($response);
}else{
$event->getForm()->addError(new FormError("Enter a mail address with valid format"), 1);
var_dump($event->getForm()->getErrors());
die("Address is not valid");
}
}
}
My problem is once i add an error, i do not know how to display it on my form like for the errors already created by the bundle.
Thanks in advance.
I would not use the Event Dispatcher component for this, I'll just go simpler and create a custom validation constraint. Here is the link to the docs.
You can create a constraint that will check if, for example, your user has an specific domain in their email. Is the constraint doesn't pass, validation will fail, and thus, the registration process, giving you proper error information.
The docs explain it really well, but if you need help with the implementation let me know and I can update my answer.
UPDATE:
class RegistrationForm extends OtherForm
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options);
$builder
->add('firstName', TextType::class, [
'required' => true,
'constraints' => [
new NotBlank(),
new Length(['min' => 2, 'max' => 20]),
]
])
->add('lastName', TextType::class, [
'required' => true,
'constraints' => [
new NotBlank(),
new Length(['min' => 2, 'max' => 20]),
]
])
->add('secondLastName', TextType::class, [
'required' => true,
'constraints' => [
new NotBlank(),
new Length(['min' => 2, 'max' => 20]),
]
])
->add('email', TextType::class, [
'required' => true,
'constraints' => [
new NotBlank(),
new CustomConstraint(),
new Length(['min' => 2, 'max' => 20]),
]
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => User::class,
'csrf_protection' => false,
'allow_extra_fields' => true,
]);
}

Symfony2 FOSUserBundle override profile form : field form empty?

I overrided registration form from FOSUserBundle with additionals fields: it works well.
When I apply the same logic to override Profile Form : the form appears well with my additionals fields but all is empty (the fields do not contain values ​​of the connected user).
Note: when I use the default form from the bundle the profile form contains the values ​​of the connected user.
Is there a specific action compared to override the registration form to retrieve the values ​​of the connected user ?
HERE IS CODE :
src/Vn/UserBundle/Resources/config/services.yml
services:
...
vn_user.profile.form.type:
class: Vn\UserBundle\Form\Type\ProfileFormType
arguments: [%fos_user.model.user.class%]
tags:
- { name: form.type, alias: vn_user_profile }
vn_user.form.handler.profile:
class: Vn\UserBundle\Form\Handler\ProfileFormHandler
arguments: ["#fos_user.profile.form", "#request", "#fos_user.user_manager"]
scope: request
public: false
symfony/app/config/config.yml
fos_user:
...
profile:
form:
type: vn_user_profile
handler: vn_user.form.handler.profile
src/Vn/UserBundle/Form/Type/ProfileFormType.php
namespace Vn\UserBundle\Form\Type;
use Symfony\Component\Form\FormBuilder;
use FOS\UserBundle\Form\Type\ProfileFormType as BaseType;
class ProfileFormType extends BaseType
{
public function buildUserForm(FormBuilder $builder, array $options)
{
parent::buildUserForm($builder, $options);
// custom field
$builder->add('profile',new MyProfileFormType(),array(
'label' => 'PROFILE'
));
}
public function getName()
{
return 'vn_user_profile';
}
}
src/Vn/UserBundle/Form/Type/MyProfileFormType.php
namespace Vn\UserBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
class MyProfileFormType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('birthday','birthday', array(
'input' => 'array',
'widget' => 'choice',
'label' => 'Birthday',
))
->add('firstname','text', array(
'trim' => true,
'label' => 'Firstname',
))
->add('lastname','text', array(
'trim' => true,
'label' => 'Lastname',
))
->add('gender','choice', array(
'choices' => array('1' => 'Male', '2' => 'Female'),
'expanded' => true,
'required' => true,
'label' => 'Vous êtes',
));
}
public function getName()
{
return 'vn_user_myprofile';
}
public function getDefaultOptions(array $options)
{
return array(
'data_class' => 'Vn\UserBundle\Document\Profile',
);
}
}
I found the mistake in my file ProfilFormeHandler.php : in the function process() I called parent::onSucess() instead of parent::process() ...
The result is a "silent" bug (silent because not fatal error appears) due to my fault of course
Thanks for time you spent to try to help me, very sorry !
<?php
// src/Vn/UserBundle/Form/Handler/RegistrationFormHandler.php
namespace Vn\UserBundle\Form\Handler;
use FOS\UserBundle\Form\Handler\ProfileFormHandler as BaseHandler;
use FOS\UserBundle\Model\UserInterface;
class ProfileFormHandler extends BaseHandler
{
public function process(UserInterface $user)
{
//parent::onSuccess($user);
parent::process($user); // sound better of course : )
}
protected function onSuccess(UserInterface $user)
{
$this->userManager->updateUser($user);
}
}

Resources