Answer the question
In order to leave comments, you need to log in
How to make form-types replaceable in symfony3?
Essence of the problem:
There is a document. The document has approvals. Lots of different matchers. For example, let's take 2x: the curator and the initiator. When creating a document, the user selects a curator from the list of users with the role "ROLE_CURATOR", and selects an initiator from the list of users with the role of initiator.
Approvers are an instance of the Approver entity. entity schema:
Finance\ExpBundle\Entity\Approver:
type: entity
table: exp_approver
id:
id:
type: integer
nullable: false
options:
unsigned: true
id: true
generator:
strategy: IDENTITY
manyToOne:
user:
targetEntity: \AppBundle\Entity\User
joinColumn:
name: user_id
referencedColumnName: id
role:
targetEntity: \AppBundle\Entity\Role
joinColumn:
name: role_id
referencedColumnName: id
document:
targetEntity: Finance\ExpBundle\Entity\Document
inversedBy: approvers
joinColumn:
name: document_id
referencedColumnName: id
public function createAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$doc = new Document();
$sSignatureCur = new UserApprover();
$sSignatureCur->setRole($em->getRepository(\AppBundle\Entity\Role::class)
->findOneBy(['name' => 'ROLE_CURATOR']));
$sSignatureCur->setDocument($doc);
$sSignatureIni = new UserApprover();
$sSignatureIni->setRole($em->getRepository(\AppBundle\Entity\Role::class)
->findOneBy(['name' => 'ROLE_INITIATOR']));
$sSignatureIni->setDocument($doc);
$doc->getApprovers()->add($sSignatureIni);
$doc->getApprovers()->add($sSignatureCur);
$form = $this->createForm(DocumentType::class, $doc);
$form->handleRequest($request);
if ( $form->isSubmitted() && $form->isValid() ) {
$em = $this->getDoctrine()->getManager();
foreach ($doc->getApprovers() as $approver){
$em->persist($approver);
}
// ...
return $this->redirectToRoute('finance_exp_view', ['id' => $doc->getId()]);
}
return $this->render('::doc.create.html.twig', [
'form' => $form->createView()
]);
}
class DocumentType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class, [
'label' => 'Предмет договора',
])
->add('approvers', CollectionType::class, array(
'entry_type' => ApproverType::class
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Document::class,
));
}
}
class ApproverType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
// фильтруем юзеров по роли
$signers = function (EntityRepository $er, $roleName){
$qb = $er->createQueryBuilder('u')
->innerJoin('u.userRoles','r')
->where('r.name=?1')
->setParameter(1, $roleName)
->orderBy('u.lastName', 'ASC')
;
return $qb;
};
$builder->add('user', EntityType::class, [
'class' => 'AppBundle:User',
'label' => 'Согласующий',
'choice_label' => function ($user) {
return $user->getFullName() . $absent;
},
'query_builder' => function(EntityRepository $er) use ($signers) {
return $signers($er, 'ROLE_CURATOR');
},
'placeholder' => '--- Выберите ---'
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Approver::class,
));
}
}
$sSignatureCur = new UserApprover();
$sSignatureCur->setRole($em->getRepository(\AppBundle\Entity\Role::class)
->findOneBy(['name' => 'ROLE_CURATOR']));
$doc->getApprovers()->add($sSignatureCur);
Answer the question
In order to leave comments, you need to log in
To get data in a form, use symfony.com/doc/current/form/events.html
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event){
if (!$data = $event->getData()) {
return;
}
$form = $event->getForm();
// Тут можно в зависимо от $data навешивать свои поля
$form
->add('someField', TextType::class)
;
});
}
As an option:
1) Register the form as a service
app.form.type.emergency:
class: AppBundle\Form\Type\ApproverType
arguments:
- "@service_container"
tags:
- { name: form.type }
/**
* @param ContainerInterface $container
*/
public function __construct(ContainerInterface $container)
{
$this->user = $container->get('security.token_storage')->getToken()->getUser();
}
I solved the problem with BoShurik's
comments. I'm posting
the code of the result.
Visually, the form looks like this:
Action for creating a new document:
public function createAction(Request $request)
{
$doc = new Document();
$roleCurator = $this->getRole('ROLE_FINANCE_CURATOR');
$userApproverCurator = new UserApprover();
$userApproverCurator->setRole($roleCurator);
$userApproverCurator->setDocument($doc);
$roleInitiator = $this->getRole('ROLE_FINANCE_INITIATOR');
$userApproverInitiator = new UserApprover();
$userApproverInitiator->setRole($roleInitiator);
$userApproverInitiator->setDocument($doc);
$doc->getApprovers()->add($userApproverInitiator);
$doc->getApprovers()->add($userApproverCurator);
$form = $this->createForm(DocumentType::class, $doc);
$form->handleRequest($request);
if ( $form->isSubmitted() && $form->isValid() ) {
$em = $this->getDoctrine()->getManager();
foreach ($doc->getApprovers() as $approver){
$em->persist($approver);
}
// ... other code
$em->persist($doc);
$em->flush();
return $this->redirectToRoute('finance_exp_view', ['id' => $doc->getId()]);
}
return $this->render('::doc.create.html.twig', [
'form' => $form->createView()
]);
}
class DocumentType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class, [
'label' => 'Предмет договора',
])
->add('price', NumberType::class, [
'label' => 'Цена',
'scale' => 2,
'grouping' => NumberFormatter::GROUPING_USED
])
// ... other fields
->add('approvers', CollectionType::class, [
'entry_type' => ApproverType::class
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Document::class,
));
}
}
class ApproverType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$listener = function (FormEvent $event) use($builder) {
/** @var UserApprover $approver */
if (!$approver = $event->getData()) {
return;
}
$form = $event->getForm();
$form->add('user', EntityType::class, [
'class' => 'AppBundle:User',
'label' => $approver->getRole()->getTitle(),
'choice_label' => function ($user) {
/** @var User $user */
$absent = (!$user->getAbsent()) ? '' : ' (отсутствует)';
return $user->getFullName() . $absent;
},
'query_builder' => function (EntityRepository $er) use ($approver){
$qb = $er->createQueryBuilder('u')
->innerJoin('u.userRoles','r')
->where('r.name=?1')
->setParameter(1, $approver->getRole()->getName())
->orderBy('u.lastName', 'ASC')
;
return $qb;
},
'placeholder' => '--- Выберите ---'
]);
};
$builder->addEventListener(FormEvents::PRE_SET_DATA, $listener);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Approver::class,
));
}
}
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question