Multi-Forms
Let's say you want to handle different variants for an Entity, but in one Entity List.
For instance, maybe you are a car-seller and you want to display all sold cars on an Entity List. Easy enough, you create a Car
entity, list and form. But now let's say you want the to handle different form fields for cars with an internal combustion engine and those with an electric engine; you can of course use a single form and conditional display to achieve this, but in a case where there are many differences, the best option is to split the Entity in two (or more) Forms. That's Multi-Form.
Write the Form classes
Following up the car example, we would write two Form classes: CombustionCarForm
and ElectricCarForm
, maybe. They are regular SharpForm
classes, as described here.
Note that you'll probably be able to regroup some common code in a trait or by inheritance: it's up to you.
Same goes for Validators, if needed.
Configuration
Once the classes are written, you must declare the forms in the sharp config file. So instead of:
// config/sharp.php
return [
"entities" => [
"car" => [
"list" => \App\Sharp\CarSharpList::class,
"form" => \App\Sharp\CarSharpForm::class,
"validator" => \App\Sharp\CarSharpValidator::class
]
]
];
You'll have something like:
// config/sharp.php
return [
"entities" => [
"car" => [
"list" => \App\Sharp\CarSharpList::class,
"forms" => [
"combustion" => [
"form" => \App\Sharp\CombustionCarSharpForm::class,
"validator" => \App\Sharp\CombustionCarSharpValidator::class,
],
"electric" => [
"form" => \App\Sharp\ElectricCarSharpForm::class,
"validator" => \App\Sharp\ElectricCarSharpValidator::class,
]
]
]
]
];
At this stage, you need only one more thing: configure the Entity List to handle Multi-Form.
The Entity List
Now we want to "merge" our Car entity in the Entity List, and allow the user to create or edit either a combustion or an electric car.
To achieve this final step, you'll have to first update the global configuration to add a label and an optional icon to each type:
// config/sharp.php
return [
"entities" => [
"car" => [
"list" => \App\Sharp\CarSharpList::class,
"forms" => [
"combustion" => [
"label" => "Combustion car",
"icon" => "fa-truck"
[...]
],
"electric" => [
"label" => "Electric car",
"icon" => "fa-car",
[...]
]
]
]
]
];
This allows the "new" button to display a dropdown with each type, leading to the right Form.
Last, you must configure an instance attribute to disambiguate each type: each instance must have this attribute valuated either with "electric" or "combustion", in our example.
You declare this attribute in the Entity List buildListConfig()
method:
function buildListConfig()
{
$this->setSearchable()
->setDefaultSort("name", "asc")
->setMultiformAttribute("engine")
->setPaginated();
}
Here, the engine
attribute must be filled for each Car instance. So how you do that? Obviously, the first way is to keep the same attribute you use in your database: in many cases, you already have this engine
value in a column. If not, or if the value is something less readable (an ID for instance), use a custom transformer:
function getListData(EntityListQueryParams $params)
{
return $this
->setCustomTransformer("engine", function($value, $car) {
return $car->motor == "EV" ? "electric" : "combustion";
})
->transform(Car::paginate(30));
}