Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FormField] Add new propertyNameSuffix to + Consistency between open & close #6555

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/Dto/FieldDto.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ final class FieldDto
{
private ?string $fieldFqcn = null;
private ?string $propertyName = null;
private ?string $propertyNameSuffix = null;
private mixed $value = null;
private mixed $formattedValue = null;
private $formatValueCallable;
Expand Down Expand Up @@ -160,6 +161,26 @@ public function setProperty(string $propertyName): void
$this->propertyName = $propertyName;
}

public function getPropertyNameSuffix(): ?string
{
return $this->propertyNameSuffix;
}

public function setPropertyNameSuffix(?string $propertyNameSuffix): void
{
$this->propertyNameSuffix = $propertyNameSuffix;
}

public function getPropertyNameWithSuffix(): string
{
return sprintf(
'%s%s%s',
$this->propertyName,
null !== $this->propertyNameSuffix ? '_' : '',
$this->propertyNameSuffix ?? '',
);
}

/**
* Returns the original unmodified value stored in the entity field.
*/
Expand Down
112 changes: 63 additions & 49 deletions src/Factory/FormLayoutFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -164,17 +164,18 @@ private function linearizeLayoutConfiguration(FieldCollection $fields): void
};
}

$aFormColumnIsOpen = false;
$aFormTabIsOpen = false;
$aFormFieldsetIsOpen = false;
$openedFormColumnDto = null;
$openedFormColumnGroupDto = null;
$openedFormTabDto = null;
$openedFormFieldsetDto = null;
$isFirstFormColumn = true;
$tabsWithoutLabelCounter = 0;

$slugger = new AsciiSlugger();
$tabs = [];
/** @var FieldDto $fieldDto */
foreach ($fields as $fieldDto) {
if ($formUsesColumns && !($aFormColumnIsOpen || $aFormTabIsOpen) && !$fieldDto->isFormLayoutField()) {
if ($formUsesColumns && !(null !== $openedFormColumnDto || null !== $openedFormTabDto) && !$fieldDto->isFormLayoutField()) {
throw new \InvalidArgumentException(sprintf('When using form columns, all fields must be rendered inside a column. However, your field "%s" does not belong to any column. Move it under a form column or create a new form column before it.', $fieldDto->getProperty()));
}

Expand All @@ -192,30 +193,31 @@ private function linearizeLayoutConfiguration(FieldCollection $fields): void

$tabs[$tabId] = $fieldDto;

if ($aFormFieldsetIsOpen) {
$fields->insertBefore($this->createFieldsetCloseField(), $fieldDto);
$aFormFieldsetIsOpen = false;
if (null !== $openedFormFieldsetDto) {
$fields->insertBefore($this->createFieldsetCloseField($openedFormFieldsetDto), $fieldDto);
$openedFormFieldsetDto = null;
}

if ($aFormColumnIsOpen) {
$fields->insertBefore($this->createColumnCloseField(), $fieldDto);
$fields->insertBefore($this->createColumnGroupCloseField($formUsesTabs), $fieldDto);
$aFormColumnIsOpen = false;
if (null !== $openedFormColumnDto) {
$fields->insertBefore($this->createColumnCloseField($openedFormColumnDto), $fieldDto);
$fields->insertBefore($this->createColumnGroupCloseField($formUsesTabs, $openedFormColumnGroupDto), $fieldDto);
$openedFormColumnDto = null;
$openedFormColumnGroupDto = null;
}

if ($aFormTabIsOpen) {
$fields->insertBefore($this->createTabPaneCloseField(), $fieldDto);
if (null !== $openedFormTabDto) {
$fields->insertBefore($this->createTabPaneCloseField($openedFormTabDto), $fieldDto);
}

$aFormTabIsOpen = true;
$openedFormTabDto = $fieldDto;
}

if ($fieldDto->isFormFieldset()) {
if ($aFormFieldsetIsOpen) {
$fields->insertBefore($this->createFieldsetCloseField(), $fieldDto);
if (null !== $openedFormFieldsetDto) {
$fields->insertBefore($this->createFieldsetCloseField($openedFormFieldsetDto), $fieldDto);
}

$aFormFieldsetIsOpen = true;
$openedFormFieldsetDto = $fieldDto;

$fieldDto->setFormTypeOptions([
'ea_css_class' => $fieldDto->getCssClass(),
Expand All @@ -230,119 +232,131 @@ private function linearizeLayoutConfiguration(FieldCollection $fields): void
$formUsesColumns = true;

if ($isFirstFormColumn) {
$fields->insertBefore($this->createColumnGroupOpenField($formUsesTabs), $fieldDto);
$fields->insertBefore($openedFormColumnGroupDto = $this->createColumnGroupOpenField($formUsesTabs), $fieldDto);
$isFirstFormColumn = false;
}

if ($aFormFieldsetIsOpen) {
$fields->insertBefore($this->createFieldsetCloseField(), $fieldDto);
$aFormFieldsetIsOpen = false;
if (null !== $openedFormFieldsetDto) {
$fields->insertBefore($this->createFieldsetCloseField($openedFormFieldsetDto), $fieldDto);
$openedFormFieldsetDto = null;
}

if ($aFormColumnIsOpen) {
$fields->insertBefore($this->createColumnCloseField(), $fieldDto);
if (null !== $openedFormColumnDto) {
$fields->insertBefore($this->createColumnCloseField($openedFormColumnDto), $fieldDto);
}

$aFormColumnIsOpen = true;
$openedFormColumnDto = $fieldDto;
}

if ($aFormColumnIsOpen) {
if (null !== $openedFormColumnDto) {
// this is needed because fields inside columns look better when they take the
// entire width available; users can override this by setting custom CSS classes
$fieldDto->setDefaultColumns('col-12');
}
}

if ($aFormFieldsetIsOpen) {
$fields->add($this->createFieldsetCloseField());
if (null !== $openedFormFieldsetDto) {
$fields->add($this->createFieldsetCloseField($openedFormFieldsetDto));
}

if ($aFormColumnIsOpen) {
$fields->add($this->createColumnCloseField());
$fields->add($this->createColumnGroupCloseField($formUsesTabs));
if (null !== $openedFormColumnDto) {
$fields->add($this->createColumnCloseField($openedFormColumnDto));
$fields->add($this->createColumnGroupCloseField($formUsesTabs, $openedFormColumnGroupDto));
}

if ($formUsesTabs) {
$fields->add($this->createTabPaneCloseField());
$fields->add($this->createTabPaneGroupCloseField());
$fields->prepend($this->createTabPaneGroupOpenField());
$fields->add($this->createTabPaneCloseField($openedFormTabDto));

$fields->prepend($openedTabPaneGroupDto = $this->createTabPaneGroupOpenField());
$fields->add($this->createTabPaneGroupCloseField($openedTabPaneGroupDto));

$fields->prepend($this->createTabListField($tabs));
}

// if the form doesn't use any layout fields (tabs, columns, fieldsets, etc.),
// wrap all fields inside a fieldset to simplify the rendering of the form later
// (by default, this fieldset is invisible and doesn't change the form layout, so it's fine)
if (!$formUsesTabs && !$formUsesColumns && !$formUsesFieldsets) {
$fields->prepend($this->createFieldsetOpenField());
$fields->add($this->createFieldsetCloseField());
$fields->prepend($openedFormFieldsetDto = $this->createFieldsetOpenField());
$fields->add($this->createFieldsetCloseField($openedFormFieldsetDto));
}
}

private function createColumnGroupOpenField(bool $formUsesTabs): FieldDto
{
return Field::new(sprintf('ea_form_column_group_open_%s', Ulid::generate()))
return Field::new('ea_form_column_group_open')
->setPropertySuffix(Ulid::generate())
->setFormType(EaFormColumnGroupOpenType::class)
->setFormTypeOptions(['mapped' => false, 'required' => false, 'ea_is_inside_tab' => $formUsesTabs])
->getAsDto();
}

private function createColumnGroupCloseField(bool $formUsesTabs): FieldDto
private function createColumnGroupCloseField(bool $formUsesTabs, ?FieldDto $openedDto): FieldDto
{
return Field::new(sprintf('ea_form_column_group_close_%s', Ulid::generate()))
return Field::new('ea_form_column_group_close')
->setPropertySuffix($openedDto?->getPropertyNameSuffix() ?? Ulid::generate())
->setFormType(EaFormColumnGroupCloseType::class)
->setFormTypeOptions(['mapped' => false, 'required' => false, 'ea_is_inside_tab' => $formUsesTabs])
->getAsDto();
}

private function createColumnCloseField(): FieldDto
private function createColumnCloseField(?FieldDto $openedDto): FieldDto
{
return Field::new(sprintf('ea_form_column_close_%s', Ulid::generate()))
return Field::new('ea_form_column_close')
->setPropertySuffix($openedDto?->getPropertyNameSuffix() ?? Ulid::generate())
->setFormType(EaFormColumnCloseType::class)
->setFormTypeOptions(['mapped' => false, 'required' => false])
->getAsDto();
}

private function createFieldsetOpenField(): FieldDto
{
return FormField::addFieldset()->getAsDto();
return FormField::addFieldset()
->setPropertySuffix(Ulid::generate())
->getAsDto();
}

private function createFieldsetCloseField(): FieldDto
private function createFieldsetCloseField(?FieldDto $openedDto): FieldDto
{
return Field::new(sprintf('ea_form_fieldset_close_%s', Ulid::generate()))
return Field::new('ea_form_fieldset_close')
->setPropertySuffix($openedDto?->getPropertyNameSuffix() ?? Ulid::generate())
->setFormType(EaFormFieldsetCloseType::class)
->setFormTypeOptions(['mapped' => false, 'required' => false])
->getAsDto();
}

private function createTabPaneGroupOpenField(): FieldDto
{
return Field::new(sprintf('ea_form_tabpane_group_open_%s', Ulid::generate()))
return Field::new('ea_form_tabpane_group_open')
->setPropertySuffix(Ulid::generate())
->setFormType(EaFormTabPaneGroupOpenType::class)
->setFormTypeOptions(['mapped' => false, 'required' => false])
->getAsDto();
}

private function createTabPaneGroupCloseField(): FieldDto
private function createTabPaneGroupCloseField(?FieldDto $openedDto): FieldDto
{
return Field::new(sprintf('ea_form_tabpane_group_close_%s', Ulid::generate()))
return Field::new('ea_form_tabpane_group_close')
->setPropertySuffix($openedDto?->getPropertyNameSuffix() ?? Ulid::generate())
->setFormType(EaFormTabPaneGroupCloseType::class)
->setFormTypeOptions(['mapped' => false, 'required' => false])
->getAsDto();
}

private function createTabListField(array $tabs): FieldDto
{
return Field::new(sprintf('ea_form_tablist_%s', Ulid::generate()))
return Field::new('ea_form_tablist')
->setPropertySuffix(Ulid::generate())
->setFormType(EaFormTabListType::class)
->setFormTypeOptions(['mapped' => false, 'required' => false])
->setCustomOption('tabs', $tabs)
->getAsDto();
}

private function createTabPaneCloseField(): FieldDto
private function createTabPaneCloseField(?FieldDto $openedDto): FieldDto
{
return Field::new(sprintf('ea_form_tabpane_close_%s', Ulid::generate()))
return Field::new('ea_form_tabpane_close')
->setPropertySuffix($openedDto?->getPropertyNameSuffix() ?? Ulid::generate())
->setFormType(EaFormTabPaneCloseType::class)
->setFormTypeOptions(['mapped' => false, 'required' => false])
->getAsDto();
Expand Down
16 changes: 16 additions & 0 deletions src/Field/FieldTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use EasyCorp\Bundle\EasyAdminBundle\Dto\AssetDto;
use EasyCorp\Bundle\EasyAdminBundle\Dto\FieldDto;
use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\Form\FormConfigBuilder;
use Symfony\Contracts\Translation\TranslatableInterface;

/**
Expand Down Expand Up @@ -42,6 +43,21 @@ public function setProperty(string $propertyName): self
return $this;
}

public function setPropertySuffix(string $propertyNameSuffix): self
{
if ('' === trim($propertyNameSuffix, " \t\n\r\0\v")) {
throw new \InvalidArgumentException('The suffix cannot be empty.');
}

if (!FormConfigBuilder::isValidName($propertyNameSuffix)) {
throw new \InvalidArgumentException(sprintf('The suffix "%s" is not valid. You must follow form name conventions.', $propertyNameSuffix));
}

$this->dto->setPropertyNameSuffix($propertyNameSuffix);

return $this;
}

/**
* @param TranslatableInterface|string|false|null $label
*/
Expand Down
20 changes: 12 additions & 8 deletions src/Field/FormField.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,16 @@ public static function addPanel($label = false, ?string $icon = null): self
* @param TranslatableInterface|string|false|null $label
* @param string|null $icon The full CSS classes of the FontAwesome icon to render (see https://fontawesome.com/v6/search?m=free)
*/
public static function addFieldset($label = false, ?string $icon = null): self
public static function addFieldset($label = false, ?string $icon = null, ?string $propertySuffix = null): self
{
$field = new self();
$icon = $field->fixIconFormat($icon, 'FormField::addFieldset()');

return $field
->setFieldFqcn(__CLASS__)
->hideOnIndex()
->setProperty('ea_form_fieldset_'.(new Ulid()))
->setProperty('ea_form_fieldset')
->setPropertySuffix($propertySuffix ?? Ulid::generate())
->setLabel($label)
->setFormType(EaFormFieldsetOpenType::class)
->addCssClass('field-form_fieldset')
Expand All @@ -77,7 +78,7 @@ public static function addFieldset($label = false, ?string $icon = null): self
* @param string $breakpointName The name of the breakpoint where the new row is inserted
* It must be a valid Bootstrap 5 name ('', 'sm', 'md', 'lg', 'xl', 'xxl')
*/
public static function addRow(string $breakpointName = ''): self
public static function addRow(string $breakpointName = '', ?string $propertySuffix = null): self
{
$field = new self();

Expand All @@ -89,7 +90,8 @@ public static function addRow(string $breakpointName = ''): self
return $field
->setFieldFqcn(__CLASS__)
->hideOnIndex()
->setProperty('ea_form_row_'.(new Ulid()))
->setProperty('ea_form_row')
->setPropertySuffix($propertySuffix ?? Ulid::generate())
->setFormType(EaFormRowType::class)
->addCssClass('field-form_row')
->setFormTypeOptions(['mapped' => false, 'required' => false])
Expand All @@ -100,15 +102,16 @@ public static function addRow(string $breakpointName = ''): self
/**
* @return static
*/
public static function addTab(TranslatableInterface|string|false|null $label = null, ?string $icon = null): self
public static function addTab(TranslatableInterface|string|false|null $label = null, ?string $icon = null, ?string $propertySuffix = null): self
{
$field = new self();
$icon = $field->fixIconFormat($icon, 'FormField::addTab()');

return $field
->setFieldFqcn(__CLASS__)
->hideOnIndex()
->setProperty('ea_form_tab_'.(new Ulid()))
->setProperty('ea_form_tab')
->setPropertySuffix($propertySuffix ?? Ulid::generate())
->setLabel($label)
->setFormType(EaFormTabPaneOpenType::class)
->addCssClass('field-form_tab')
Expand All @@ -124,15 +127,16 @@ public static function addTab(TranslatableInterface|string|false|null $label = n
* (e.g. 'col-6', 'col-sm-3', 'col-md-6 col-xl-4', etc.)
* (integer values are transformed like this: N -> 'col-N')
*/
public static function addColumn(int|string $cols = 'col', TranslatableInterface|string|false|null $label = null, ?string $icon = null, ?string $help = null): self
public static function addColumn(int|string $cols = 'col', TranslatableInterface|string|false|null $label = null, ?string $icon = null, ?string $help = null, ?string $propertySuffix = null): self
{
$field = new self();
// $icon = $field->fixIconFormat($icon, 'FormField::addTab()');

return $field
->setFieldFqcn(__CLASS__)
->hideOnIndex()
->setProperty('ea_form_column_'.(new Ulid()))
->setProperty('ea_form_column')
->setPropertySuffix($propertySuffix ?? Ulid::generate())
->setLabel($label)
->setFormType(EaFormColumnOpenType::class)
->addCssClass(sprintf('field-form_column %s', \is_int($cols) ? 'col-md-'.$cols : $cols))
Expand Down
Loading
Loading