问题
In a previous question I ask how to handle large forms, outcome was Single Table Inheritance (STI) or CTI, Inheritance mapping. I've has chosen for CTI.
Now i'm dealing how to create the form with CTI. A quick overview what kind or relation there are.
Each inspection
could have one or more surfaces
. Each surface consists of many sub entities, like: surface_leakage
, surface_tension
or surface_slope
. As you could see surface
has the CTI with sub entities. Some fields overlap (put them in parent), some don't (put them in child). But in the end I need one form with all the fields grouped by surfaces then by child (maybe Bootrap collapse).
Setting up the relation was not that hard, but to use it into a form is difficult and I'm not sure how I could handle this. See below code with in code two approuches
<?php
class Inspection
{
/**
* @OneToMany(targetEntity="App\Entity\Surface", mappedBy="inspection")
*/
protected $surfaces;
}
/**
* @Entity
* @InheritanceType("JOINED")
* @DiscriminatorColumn(name="discr", type="string")
* @DiscriminatorMap({"surface" = "Surface", "surface_leagage" = "SurfaceLeakage", ...})
*/
class Surface
{
protected $inpection;
protected $description;
}
class SurfaceLeakage extends Surface
{
protected $leakageLevel;
}
// .. other child classes (SurfaceTension, SurfaceSlope, ...)
class InspectionType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
// ...
$builder->add('surfaces', CollectionType::class, [
'entry_type' => SurfaceType::class,
]);
}
}
// Approach 1, where each child is added to the SurfaceType
// with this approach data should be mapped false
// This approach ensures that I only have to call SurfaceType once and all fields are loaded, but
// could not make this work with data from DB through CIT.
// Also this method does not allow me to add field description (from parent) to all childTypes
class SurfaceType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('leakage', SurfaceLeakageType::class, array('mapped' => false));
$builder->add('tension', SurfaceTensionType::class, array('mapped' => false));
// ...
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Surface::class,
]);
}
}
class SurfaceLeakageType extends AbstractType
{
}
// Approach 2, where each childFormType could extend SurfaceType, like below but how to call/create the
// form and handling the data.
// With this approuch i could parent fields to the child
class SurfaceLeakageType extends SurfaceType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('description', TextareaType::class); // field from parent or ...
parent::buildForm($builder, $options);
$builder->add('leakageLevel', IntegerType::class); // own field
// ...
}
}
Then there is form inherit_data
// Approach 3, inherit data, now each child should add this as a field like below,
// but how the only thing I'm doing on InspectionType build Surfaces as collection so
// i think inherit data also doesn't work
class SurfaceType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('description', TextareaType::class);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'inherit_data' => true,
]);
}
}
class SurfaceLeakageType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
// inherit fields
$builder->add('leakage', SurfaceType::class, [
'data_class' => SurfaceLeakage::class,
]);
$builder->add('leakageLevel', IntegerType::class); // own field
}
}
Hope someone could help me out
回答1:
I think you are looking for polymorphic forms. Check this bundle https://github.com/infinite-networks/InfiniteFormBundle
来源:https://stackoverflow.com/questions/64975018/symfony-form-with-doctrine-class-table-inheritance-cti