I have two entoty User and Location and I crate model with two entity and create form for this model and add validate_group for this form? but ahen I check form is valid - form always valid, but entity is emthy and entity have assert not blank fields, what I'am doing wrong ?
entities
class User implements UserInterface, \JsonSerializable
{
use GedmoTrait;
/**
* #var integer
*
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #Assert\NotBlank(groups={"admin_user_post"})
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $firstName;
class Location
{
/**
* #var integer
*
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #Assert\NotBlank(groups={"admin_user_post"})
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $address;
create form
class CreateUser extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('user', new UserType(), ['validation_groups' => ['admin_user_post']]);
$builder->add('location', new LocationType(), ['validation_groups' => ['admin_user_post']]);
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AdminBundle\Model\CreateUserModel',
'csrf_protection' => false,
'validation_groups' => ['admin_user_post']
));
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('firstName')
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\User',
'csrf_protection' => false,
'validation_groups' => ['admin_user_post']
));
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('address')
->add('cityObject', null, array('attr' => array('placeholder' => 'Select city')));
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Location',
'csrf_protection' => false,
'validation_groups' => ['admin_user_post']
));
}
and action
$entity = new CreateUserModel();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()
&& $form->get('user')->isValid()
&& $form->get('location')->isValid()
) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity->getLocation());
$entity->getUser()->setLocation($entity->getLocation());
$em->persist($entity->getUser());
$em->flush();
$user = $entity->getUser();
return $this->redirect($this->generateUrl('admin_users_show', array('id' => $user->getId())));
}
/**
* Creates a form to create a User entity.
*
* #param CreateUserModel $entity The entity
*
* #return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(CreateUserModel $entity)
{
$form = $this->createForm(new CreateUser(), $entity, array(
'validation_groups' => ['admin_user_post'],
'action' => $this->generateUrl('admin_users_create'),
'method' => 'POST',
));
$form->add('submit', 'submit', array('label' => 'Create'));
return $form;
}
I try in action
$error = $this->get('validator')->validate($form->getData()->getUser(), ['admin_create_user']);
but still have empty $error
Why form is valid true ? or how correct valid form model with my entities and assert in this entities ?
Add to 'CreateUser' form 'cascade_validation' option to validate nested forms, and check that's annotation method for your constrains was specified at config.yml
# app/config/config.yml
framework:
validation: { enable_annotations: true }
Related
I have following collection called config_settings in my mongo db
/**
* #MongoDB\Document(collection="config_settings", repositoryClass="AppBundle\Repository\SettingRepository")
* #MongoDB\HasLifecycleCallbacks()
*/
class Setting
{
/**
* #MongoDB\Id()
* #var ObjectId $id
*/
protected $id;
/**
* #MongoDB\Field(type="string")
* #var string $name
*/
protected $name;
/**
* #MongoDB\Field(type="raw")
* #var array<array> $value
*/
protected $value;
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #param mixed $id
*/
public function setId($id): void
{
$this->id = $id;
}
/**
* #return mixed
*/
public function getName()
{
return $this->name;
}
/**
* #param mixed $name
*/
public function setName($name): void
{
$this->name = $name;
}
/**
* #return mixed
*/
public function getValue()
{
return $this->value;
}
/**
* #param mixed $value
*/
public function setValue($value): void
{
$this->value = $value;
}
}
I have a form that take values and name and saved it to the database a follow
<?php
namespace AppBundle\Form;
use AppBundle\Document\Setting;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class SettingCollectionType extends AbstractType
{
/**
* {#inheritdoc}
* #param FormBuilderInterface<string|FormBuilderInterface> $builder
* #param array<array> $options
* #return void
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$choices = [];
foreach ($options['featureKeys'] as $key) {
$choices[$key] = $key;
}
$builder
->add('name', ChoiceType::class, [
'label' => 'Feature',
'choices' => $choices,
'required' => true,
])
->add('value', CollectionType::class, array(
'entry_type' => TextType::class,
'prototype' => true,
'allow_add' => true,
'allow_delete' => true,
'label' => false,
))
->add('submit', SubmitType::class, [
'attr' => [
'class' => 'btn btn-outline-secondary'
],
]);
}
/**
* {#inheritdoc}
* #param OptionsResolver $resolver
* #return void
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Setting::class,
'featureKeys' => null
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return '';
}
}
So here is the problem, whenever I try to update the form and change the value, it always flush and saved it as an object instead of saving it as an array.
This is before flushing into my database.
And this is after flushed into my database.
Here is how i saved form inside my controller and it is very simple.
if ('POST' === $request->getMethod()) {
$form->handleRequest($request);
if ($form->isValid()) {
$dm->persist($entity);
$dm->flush();
}
}
Am i doing something wrong ?
MongoDB needs to have an array with consecutive indices to have it saved as an array in the database. Most probably it's not hence it's being saved as an object (with numeric keys I presume). Try using a collection type for your value field as it ensures what you're saving to the database is in fact a list. What collection does behind a scene is an additional array_values call while raw type saves the data as is.
I have crud with 3 entities. Meal, Product and ProductsQuantity. Between Meal and ProductQuantity is relation many to many. Adding data is working fine, all data are saving to entities but problem is when in want to edit form. Then I got error:
The form's view data is expected to be an instance of class MealBundle\Entity\ProductsQuantity, but is an instance of class Doctrine\ORM\PersistentCollection. You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms an instance of class Doctrine\ORM\PersistentCollection to an instance of MealBundle\Entity\ProductsQuantity.
I tried with data_class option to null, and setting fetch="EAGER" on the relation but it doesn't solved the problem.
Meal:
/**
* #Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
protected $id;
/**
* #var string
* #ORM\Column(name="name", type="string", length=255)
*/
protected $name = "";
/**
* #var ProductsQuantity[]|Collection
* #ORM\ManyToMany(targetEntity="ProductsQuantity", inversedBy="meal", cascade={"persist"}, fetch="EAGER")
* #ORM\JoinTable(name="meal_products_quantity_relations",
* joinColumns={#ORM\JoinColumn(name="meal_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="products_quantity_id", referencedColumnName="id")}
* )
*/
protected $productsQuantity;
/**
* Meal constructor.
*/
public function __construct()
{
$this->productsQuantity = new ArrayCollection();
}
/**
* #return int
*/
public function getId(): int
{
return $this->id;
}
/**
* #param int $id
* #return Meal
*/
public function setId(int $id): Meal
{
$this->id = $id;
return $this;
}
/**
* #return string
*/
public function getName(): string
{
return $this->name;
}
/**
* #param string $name
* #return Meal
*/
public function setName(string $name): Meal
{
$this->name = $name;
return $this;
}
/**
* #return Collection|ProductsQuantity[]
*/
public function getProductsQuantity()
{
return $this->productsQuantity;
}
/**
* #param Collection|ProductsQuantity[] $productsQuantity
* #return Meal
*/
public function setProductsQuantity($productsQuantity)
{
$this->productsQuantity = $productsQuantity;
return $this;
}
ProductQuantity:
/**
* #Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
protected $id;
/**
* #var Product
* #ORM\JoinColumn(name="product_id", referencedColumnName="id")
* #ORM\ManyToOne(targetEntity="Product", inversedBy="productsQuantity")
*/
protected $product;
/**
* #var integer
* #ORM\Column(name="amount", type="integer")
*/
protected $amount;
/**
* #var $meal
* #ORM\ManyToMany(targetEntity="MealBundle\Entity\Meal", mappedBy="productsQuantity")
*/
protected $meal;
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #param mixed $id
* #return ProductsQuantity
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
/**
* #return Product
*/
public function getProduct(): ?Product
{
return $this->product;
}
/**
* #param Product $product
* #return ProductsQuantity
*/
public function setProduct(Product $product): ProductsQuantity
{
$this->product = $product;
return $this;
}
/**
* #return int
*/
public function getAmount(): ?int
{
return $this->amount;
}
/**
* #param int $amount
*/
public function setAmount(int $amount): void
{
$this->amount = $amount;
}
/**
* #return mixed
*/
public function getMeal()
{
return $this->meal;
}
/**
* #param mixed $meal
* #return ProductsQuantity
*/
public function setMeal($meal)
{
$this->meal = $meal;
return $this;
}
Meal form:
class MealType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options = [])
{
parent::buildForm($builder, $options);
/** #var Meal $meal */
$meal = $options['data'];
$data = null;
if(!empty($meal)) {
$data = $meal->getProductsQuantity();
} else {
$data = new ProductsQuantity();
}
$builder
->add('name', TextType::class,[
'label' => 'Nazwa Dania',
'required' => true
])->add('productsQuantity', CollectionType::class, [
'data_class' => null,
'label' => 'Produkty',
'entry_type' => ProductsQuantityType::class,
'allow_add' => true,
'data' => ['productsQuantity' => $data],
'prototype_name' => '__product__',
'entry_options' => [
'allow_extra_fields' => true,
'label' => false
],
'prototype' => true
])->add('addProduct', ButtonType::class, [
'label' => 'Dodaj kolejny produkt',
'attr' => [
'class' => 'btn-default addProductEntry'
]
])->add('submit', SubmitType::class, [
'label' => 'Dodaj'
]);
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setRequired('productsQuantity');
$resolver->setDefaults([
'data_class' => Meal::class
]);
}
}
ProductsQuantity form:
class ProductsQuantityType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options);
$builder
->add('product', EntityType::class,[
'class' => Product::class,
'label' => 'Nazwa produktu',
])
->add('amount', NumberType::class, [
'label' => 'Ilość',
'required' => true,
'attr' => [
'placeholder' => 'ilość'
]
])
->add('removeProduct', ButtonType::class, [
'label' => 'X',
'attr' => [
'class' => 'btn-danger removeProductEntry'
]
]);
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => ProductsQuantity::class,
]);
}
}
If I change 'data' => ['productsQuantity' => $data] to 'data' => ['productsQuantity' => new ProductsQuantity()] there is no error but have empty ProductsQuantity part of MealType form. Can anyone tell me how to fix this?
I am trying to submit a JSON through a complex form. I can't figure out what I am missing. The "normal" form is functioning. I am able to get serialized data with groups.
Class TaskBoard
class TaskBoard
{
/**
* #var integer $id id
*
* #ORM\Id()
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
*/
private $id;
/**
* #var \DateTime $createdTime createdTime
*
* #ORM\Column(type="datetime")
* #Assert\DateTime()
*/
private $createdTime;
/**
* #var \DateTime $lastUpdatedTime lastUpdatedTime
*
* #ORM\Column(type="datetime", nullable=true)
* #Assert\DateTime()
*/
private $lastUpdatedTime;
/**
* #var string $name name
*
* #ORM\Column(type="string", length=20)
* #Assert\Type("string")
* #Assert\NotBlank()
* #Assert\Length(
* min = 2,
* max = 20,
* minMessage = "The name must be at least {{ limit }} characters long",
* maxMessage = "The name cannot be longer than {{ limit }} characters"
* )
*/
private $name;
/**
* #var App\Entity\User $user user
*
* #ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="taskboards", cascade={"persist"})
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $user;
/**
* #var string $description description
*
* #ORM\Column(type="text", nullable=true)
* #Assert\Type("string")
*/
private $description;
/**
* #var App\Entity\Status $status status
*
* #ORM\ManyToOne(targetEntity="App\Entity\Status", inversedBy="taskboards", cascade={"persist"})
* #ORM\JoinColumn(name="status_id", referencedColumnName="id", nullable=false)
*/
private $status;
/**
* #var boolean $completed completed
*
* #ORM\Column(type="boolean")
*/
private $completed;
/**
* #var \DateTime $deadLine deadLine
*
* #ORM\Column(type="date", nullable=true)
* #Assert\DateTime()
* #Assert\GreaterThanOrEqual("today")
*/
private $deadLine;
Class Status
class Status
{
/**
* #ORM\Id()
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=20)
*/
private $name;
/**
* #ORM\OneToMany(targetEntity="App\Entity\TaskBoard", mappedBy="status", cascade={"persist"})
*/
public $taskboards;
Class User
class User extends BaseUser
{
/**
* #ORM\Id()
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
*/
protected $id;
/**
* #ORM\OneToMany(targetEntity="App\Entity\TaskBoard", mappedBy="user", cascade={"persist"})
*/
public $taskboards;
Form
class TaskBoardType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('name', TextType::class)
->add('user', EntityType::class, array(
'class' => User::class,
'choice_label' => 'username',
)
)
->add('description', TextareaType::class, array(
'required' => false
))
->add('status', EntityType::class, array(
'class' => Status::class,
'choice_label' => 'name',
)
)
->add('deadLine', DateTimeType::class)
;
}
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults([
'data_class' => TaskBoard::class,
'csrf_protection' => false,
]);
}
Controller
class TaskBoardAPIController extends AbstractController {
public function postTaskBoard(Request $request) {
$form = $this->createForm(TaskBoardType::class, new TaskBoard());
$data = json_decode(
$request->getContent(), true
);
var_dump($data);
$form->submit($data);
if (!$form->isValid()) {
return new JsonResponse(
[
'status' => 'error',
'errors' => $form->getErrors(),
'form' => $form,
], JsonResponse::HTTP_BAD_REQUEST
);
}
$this->entityManager->persist($form->getData());
$this->entityManager->flush();
return new JsonResponse(
[
'status' => 'ok',
], JsonResponse::HTTP_CREATED
);
}
JSON sent
{
"name": "XXX",
"user": {
"id": 1,
"username": "BFA"
},
"description": "XXXXXXXXXXXXXXX",
"status": {
"id": 1,
"name": "To Do"
},
"completed": false
}
The form is not valid and blank in the JsonResponse.
I based myself on : https://codereviewvideos.com/course/beginners-guide-back-end-json-api-front-end-2018/video/symfony-4-json-api-form-submission
and Deserialize an entity with a relationship with Symfony Serializer Component
Thanks for your help.
What was wrong was the JSON input.
The form does this :
class TaskBoardType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('name', TextType::class)
->add('user', EntityType::class, array(
'class' => User::class,
'choice_label' => 'username',
)
)
->add('description', TextareaType::class, array(
'required' => false
))
->add('status', EntityType::class, array(
'class' => Status::class,
'choice_label' => 'name',
)
)
->add('deadLine', DateTimeType::class)
;
}
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults([
'data_class' => TaskBoard::class,
'csrf_protection' => false,
]);
}
When checking the code generated from the form, this is the result :
<div>
<label for="task_board_user" class="required">User</label>
<select id="task_board_user" name="task_board[user]">
<option value="1">XXX</option>
<option value="2">XXX</option>
</select>
</div>
Thus the form is expecting directly an INT/ID.
By changing the JSON as follow it goes through validation :
{
"name": "XXXO",
"user": 1,
"description": "XXXXXXXXXXXXXXX",
"status": 1
}
Your forgot to handle and get form submission.
Note that you will need to get request data using something like
$form = $this->createFormBuilder($task)
... add fields
->getForm();
$form->handleRequest($request); // handling request
if ($form->isSubmitted() && $form->isValid()) {
// $form->getData() holds the submitted values
// but, the original `$task` variable has also been updated
$task = $form->getData();
// ... perform some action, such as saving the task to the database
// for example, if Task is a Doctrine entity, save it!
// $entityManager = $this->getDoctrine()->getManager();
// $entityManager->persist($task);
// $entityManager->flush();
return $this->redirectToRoute('...');
}
for more, see Handling Form Submissions
I am trying to create a form with an entity collection.
Here is my code :
Colle entity :
* #ORM\Table(name="colle")
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="discr", type="string")
* #ORM\DiscriminatorMap({"colle"="Colle","colleQC"="ColleQC", "colleQR"="ColleQR"})
*/
class Colle
{
/**
* #var ArrayCollection
* #ORM\OneToMany(targetEntity="Polycopie", mappedBy="colle", cascade={"persist", "remove"})
*/
protected $polycopies;
public function __construct()
{
$this->polycopies = new ArrayCollection();
}
/**
* #return ArrayCollection
*/
public function getPolycopies()
{
return $this->polycopies;
}
/**
* Add Polycopie
*
* #param Polycopie $polycopie
* #return Colle
*/
public function addPolycopie(Polycopie $polycopie)
{
$this->polycopies[] = $polycopie;
return $this;
}
/**
* Remove Polycopie
*
* #param Polycopie $polycopie
*/
public function removePolycopie(Polycopie $polycopie)
{
$this->polycopies->removeElement($polycopie);
}
}
Polycopie entity :
class Polycopie
{
/**
* #ORM\ManyToOne(targetEntity="Colle", inversedBy="polycopies", cascade={"persist"})
* #ORM\JoinColumn(name="id_colle", referencedColumnName="id")
*/
protected $colle;
public function getColle(): ?Colle
{
return $this->colle;
}
public function setColle(Colle $colle): self
{
$this->colle = $colle;
return $this;
}
}
Form :
class MiseEnLigneFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('polycopies', CollectionType::class,
['label' => false,
'label_attr' => ['class' => 'active'],
'entry_type' => PolycopieFormType::class,
'entry_options' => [
'data_class' => Polycopie::class],
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(['data_class' => Colle::class]);
}
}
PolycopieForm :
class PolycopieFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('nom', TextType::class, ['label' =>'Nom',
'label_attr' => ['class'=>'active']]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(['data_class' => Polycopie::class]);
}
}
I keep getting this error :
Could not determine access type for property "polycopies" in class "App\Entity\ColleQC"
I tried clearing the cache but it doesn't work.
I made some research and it should be because something is missing such as a getter or setter but I can't find what is missing in my code.
Currently I have embedded entity forms in a form. And I would like the underlying data to auto populate the address fields when a user selects a project. However using the form events as shown below in the entities and the corresponding ajax code specified in the Symfony 2 documentation, the address fields are never populated in the corresponding ajax response.
Using var_dump I can see that the address is grabbed and sent to the data option when I add the address field. But it never shows up in the form response when the form is submitted with just the selected project.
Is this the proper way to do it or am I missing some vital piece somewhere? Or does symfony not do this and should I do it via jquery/ajax?
TransactionUser
class TransactionUser
{
/**
* #var string
*
* #ORM\Column(name="id", type="guid")
* #ORM\Id
*/
private $id;
/**
* The associated transaction to this TransactionUser.
*
* #var \Acme\BaseBundle\Entity\Transaction $transaction
*
* #ORM\ManyToOne(targetEntity="Acme\BaseBundle\Entity\Transaction", inversedBy="transactionUsers", cascade={"all"})
*/
private $transaction;
/**
* The Project that this TransactionUser is associated with.
*
* #var \Acme\BaseBundle\Entity\Project
*
* #ORM\ManyToOne(targetEntity="Acme\BaseBundle\Entity\Project", inversedBy="transactionUsers", cascade={"all"})
*/
private $project;
}
Transaction
class Transaction
{
/**
* #var string
*
* #ORM\Column(name="id", type="guid")
* #ORM\Id
*/
private $id;
/**
* #var \Acme\BaseBundle\Entity\Address
*
* #ORM\ManyToOne(targetEntity="Acme\BaseBundle\Entity\Address", cascade={"persist"}, inversedBy="propertyAddressTransactions")
*/
private $propertyAddress;
/**
* #ORM\OneToMany(targetEntity="Acme\BaseBundle\Entity\TransactionUser", mappedBy="transaction", cascade={"all"})
*/
private $transactionUsers;
}
Address
class Address
{
/**
* The database id for the Address.
*
* #var string
*
* #ORM\Column(name="id", type="guid")
* #ORM\Id
*/
private $id;
/**
* The first line of the street address.
*
* #var string
*
* #ORM\Column(name="streetAddressLine1", type="text")
*/
private $streetAddressLine1;
/**
* The Transactions that list this address as the property address.
*
* #ORM\OneToMany(targetEntity="Acme\BaseBundle\Entity\Transaction", mappedBy="propertyAddress")
*/
private $propertyAddressTransactions;
}
Project
class Project
{
/**
* #var string
*
* #ORM\Column(name="id", type="guid")
* #ORM\Id
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="Acme\BaseBundle\Entity\TransactionUser", mappedBy="project", cascade={"all"})
* \Doctrine\Common\Collections\ArrayCollection
*/
private $transactionUsers;
}
NewTransactionFormType
class NewTransactionFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('project', EntityType::class, array(
'class' => 'AcmeBaseBundle:Project',
'required' => false,
'optional' => true,
'label' => 'Select Project',
'placeholder' => 'Select Project',
'property' => 'projectName',
'query_builder' => function (EntityRepository $er) {
$queryBuilder = $er->createQueryBuilder('p');
return $queryBuilder;
},
));
$builder->add('transaction', NewTransactionSubFormType::class);
$builder->get('transaction')->add('propertyAddress', AddressFormType::class);
//Listeners on project to set the address
$formModifier = function (FormInterface $form, Project $project = null) {
$address = null;
if (!is_null($project) && !is_null($project->getId())) {
$address = $project->getFirstTransactionAddress();
}
$form->get('transaction')->add('propertyAddress', AddressFormType::class, array(
'data' => $address
));
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formModifier) {
// this would be your entity, i.e. Transaction
$data = $event->getData();
$formModifier($event->getForm(), $data->getProject());
}
);
$builder->get('project')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifier) {
// It's important here to fetch $event->getForm()->getData(), as
// $event->getData() will get you the client data (that is, the ID)
$project = $event->getForm()->getData();
// since we've added the listener to the child, we'll have to pass on
// the parent to the callback functions!
$formModifier($event->getForm()->getParent(), $project);
}
);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\BaseBundle\Entity\TransactionUser',
));
}
}
NewTransactionSubFormType
class NewTransactionSubFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name', TextType::class, array(
'label' => 'Name',
'attr' => array(
'class' => '',
'placeholder' => 'Name',
),
'required' => true,
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\BaseBundle\Entity\Transaction',
));
}
}
AddressFormType
class AddressFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('streetAddressLine1', TextType::class, array(
'label' => 'Street Address Line 1',
'attr' => array(
'class' => '',
'placeholder' => 'Street Address Line 1',
),
'required' => true,
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\BaseBundle\Entity\Address',
));
}
}