vendor/easycorp/easyadmin-bundle/src/Field/FormField.php line 47

Open in your IDE?
  1. <?php
  2. namespace EasyCorp\Bundle\EasyAdminBundle\Field;
  3. use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface;
  4. use EasyCorp\Bundle\EasyAdminBundle\Form\Type\EaFormRowType;
  5. use EasyCorp\Bundle\EasyAdminBundle\Form\Type\Layout\EaFormColumnOpenType;
  6. use EasyCorp\Bundle\EasyAdminBundle\Form\Type\Layout\EaFormFieldsetOpenType;
  7. use EasyCorp\Bundle\EasyAdminBundle\Form\Type\Layout\EaFormTabPaneOpenType;
  8. use Symfony\Component\Uid\Ulid;
  9. use Symfony\Contracts\Translation\TranslatableInterface;
  10. /**
  11.  * @author Javier Eguiluz <javier.eguiluz@gmail.com>
  12.  */
  13. final class FormField implements FieldInterface
  14. {
  15.     use FieldTrait;
  16.     public const OPTION_ICON 'icon';
  17.     public const OPTION_COLLAPSIBLE 'collapsible';
  18.     public const OPTION_COLLAPSED 'collapsed';
  19.     public const OPTION_ROW_BREAKPOINT 'rowBreakPoint';
  20.     public const OPTION_TAB_ID 'tabId';
  21.     public const OPTION_TAB_IS_ACTIVE 'tabIsActive';
  22.     public const OPTION_TAB_ERROR_COUNT 'tabErrorCount';
  23.     /**
  24.      * @internal Use the other named constructors instead (addPanel(), etc.)
  25.      *
  26.      * @param TranslatableInterface|string|false|null $label
  27.      */
  28.     public static function new(string $propertyName$label null)
  29.     {
  30.         throw new \RuntimeException('Instead of this method, use the "addPanel()" method.');
  31.     }
  32.     /**
  33.      * @param TranslatableInterface|string|false|null $label
  34.      * @param string|null                             $icon  The full CSS classes of the FontAwesome icon to render (see https://fontawesome.com/v6/search?m=free)
  35.      */
  36.     public static function addPanel($label false, ?string $icon null): self
  37.     {
  38.         trigger_deprecation(
  39.             'easycorp/easyadmin-bundle',
  40.             '4.7.7',
  41.             '"FormField::addPanel()" has been deprecated in favor of "FormField::addFieldset()" and it will be removed in 5.0.0.',
  42.         );
  43.         return self::addFieldset($label$icon);
  44.     }
  45.     /**
  46.      * @param TranslatableInterface|string|false|null $label
  47.      * @param string|null                             $icon  The full CSS classes of the FontAwesome icon to render (see https://fontawesome.com/v6/search?m=free)
  48.      */
  49.     public static function addFieldset($label false, ?string $icon null): self
  50.     {
  51.         $field = new self();
  52.         $icon $field->fixIconFormat($icon'FormField::addFieldset()');
  53.         return $field
  54.             ->setFieldFqcn(__CLASS__)
  55.             ->hideOnIndex()
  56.             ->setProperty('ea_form_fieldset_'.(new Ulid()))
  57.             ->setLabel($label)
  58.             ->setFormType(EaFormFieldsetOpenType::class)
  59.             ->addCssClass('field-form_fieldset')
  60.             ->setFormTypeOptions(['mapped' => false'required' => false])
  61.             ->setCustomOption(self::OPTION_ICON$icon)
  62.             ->setCustomOption(self::OPTION_COLLAPSIBLEfalse)
  63.             ->setCustomOption(self::OPTION_COLLAPSEDfalse)
  64.             ->setValue(true);
  65.     }
  66.     /**
  67.      * @param string $breakpointName The name of the breakpoint where the new row is inserted
  68.      *                               It must be a valid Bootstrap 5 name ('', 'sm', 'md', 'lg', 'xl', 'xxl')
  69.      */
  70.     public static function addRow(string $breakpointName ''): self
  71.     {
  72.         $field = new self();
  73.         $validBreakpointNames = ['''sm''md''lg''xl''xxl'];
  74.         if (!\in_array($breakpointName$validBreakpointNamestrue)) {
  75.             throw new \InvalidArgumentException(sprintf('The value passed to the "addRow()" method of "FormField" can only be one of these values: "%s" ("%s" was given).'implode(', '$validBreakpointNames), $breakpointName));
  76.         }
  77.         return $field
  78.             ->setFieldFqcn(__CLASS__)
  79.             ->hideOnIndex()
  80.             ->setProperty('ea_form_row_'.(new Ulid()))
  81.             ->setFormType(EaFormRowType::class)
  82.             ->addCssClass('field-form_row')
  83.             ->setFormTypeOptions(['mapped' => false'required' => false])
  84.             ->setCustomOption(self::OPTION_ROW_BREAKPOINT$breakpointName)
  85.             ->setValue(true);
  86.     }
  87.     /**
  88.      * @return static
  89.      */
  90.     public static function addTab(TranslatableInterface|string|false|null $label null, ?string $icon null): self
  91.     {
  92.         $field = new self();
  93.         $icon $field->fixIconFormat($icon'FormField::addTab()');
  94.         return $field
  95.             ->setFieldFqcn(__CLASS__)
  96.             ->hideOnIndex()
  97.             ->setProperty('ea_form_tab_'.(new Ulid()))
  98.             ->setLabel($label)
  99.             ->setFormType(EaFormTabPaneOpenType::class)
  100.             ->addCssClass('field-form_tab')
  101.             ->setFormTypeOptions(['mapped' => false'required' => false])
  102.             ->setCustomOption(self::OPTION_ICON$icon)
  103.             ->setCustomOption(self::OPTION_TAB_ERROR_COUNT0)
  104.             ->setValue(true);
  105.     }
  106.     /**
  107.      * @param int|string $cols Any value compatible with Bootstrap grid system
  108.      *                         (https://getbootstrap.com/docs/5.3/layout/grid/)
  109.      *                         (e.g. 'col-6', 'col-sm-3', 'col-md-6 col-xl-4', etc.)
  110.      *                         (integer values are transformed like this: N -> 'col-N')
  111.      */
  112.     public static function addColumn(int|string $cols 'col'TranslatableInterface|string|false|null $label null, ?string $icon null, ?string $help null): self
  113.     {
  114.         $field = new self();
  115.         // $icon = $field->fixIconFormat($icon, 'FormField::addTab()');
  116.         return $field
  117.             ->setFieldFqcn(__CLASS__)
  118.             ->hideOnIndex()
  119.             ->setProperty('ea_form_column_'.(new Ulid()))
  120.             ->setLabel($label)
  121.             ->setFormType(EaFormColumnOpenType::class)
  122.             ->addCssClass(sprintf('field-form_column %s'\is_int($cols) ? 'col-md-'.$cols $cols))
  123.             ->setFormTypeOptions(['mapped' => false'required' => false])
  124.             ->setCustomOption(self::OPTION_ICON$icon)
  125.             ->setValue(true);
  126.     }
  127.     public function setIcon(string $iconCssClass): self
  128.     {
  129.         $iconCssClass $this->fixIconFormat($iconCssClass'FormField::setIcon()');
  130.         $this->setCustomOption(self::OPTION_ICON$iconCssClass);
  131.         return $this;
  132.     }
  133.     public function collapsible(bool $collapsible true): self
  134.     {
  135.         if (!$this->hasLabelOrIcon()) {
  136.             throw new \InvalidArgumentException(sprintf('The %s() method used in one of your fieldsets requires that the fieldset defines either a label or an icon, but it defines none of them.'__METHOD__));
  137.         }
  138.         $this->setCustomOption(self::OPTION_COLLAPSIBLE$collapsible);
  139.         return $this;
  140.     }
  141.     public function renderCollapsed(bool $collapsed true): self
  142.     {
  143.         if (!$this->hasLabelOrIcon()) {
  144.             throw new \InvalidArgumentException(sprintf('The %s() method used in one of your fieldsets requires that the fieldset defines either a label or an icon, but it defines none of them.'__METHOD__));
  145.         }
  146.         $this->setCustomOption(self::OPTION_COLLAPSIBLEtrue);
  147.         $this->setCustomOption(self::OPTION_COLLAPSED$collapsed);
  148.         return $this;
  149.     }
  150.     private function hasLabelOrIcon(): bool
  151.     {
  152.         // don't use empty() because the label can contain only white spaces (it's a valid edge-case)
  153.         return (null !== $this->dto->getLabel() && '' !== $this->dto->getLabel())
  154.             || null !== $this->dto->getCustomOption(self::OPTION_ICON);
  155.     }
  156.     private function fixIconFormat(?string $iconstring $methodName): ?string
  157.     {
  158.         if (null === $icon) {
  159.             return $icon;
  160.         }
  161.         if (!str_contains($icon'fa-') && !str_contains($icon'far-') && !str_contains($icon'fab-')) {
  162.             trigger_deprecation('easycorp/easyadmin-bundle''4.4.0''The value passed as the $icon argument in "%s" method must be the full FontAwesome CSS class of the icon. For example, if you passed "user" before, you now must pass "fa fa-user" (or any style variant like "fa fa-solid fa-user").'$methodName);
  163.             $icon sprintf('fa fa-%s'$icon);
  164.         }
  165.         return $icon;
  166.     }
  167. }