TwigExtension.php 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. <?php declare(strict_types=1);
  2. namespace Grav\Plugin\Form;
  3. use Grav\Framework\Form\Interfaces\FormInterface;
  4. use Twig\Extension\AbstractExtension;
  5. use Twig\TwigFilter;
  6. use Twig\TwigFunction;
  7. use function is_string;
  8. /**
  9. * Class GravExtension
  10. * @package Grav\Common\Twig\Extension
  11. */
  12. class TwigExtension extends AbstractExtension
  13. {
  14. public function getFilters()
  15. {
  16. return [
  17. new TwigFilter('value_and_label', [$this, 'valueAndLabel'])
  18. ];
  19. }
  20. /**
  21. * Return a list of all functions.
  22. *
  23. * @return array
  24. */
  25. public function getFunctions(): array
  26. {
  27. return [
  28. new TwigFunction('prepare_form_fields', [$this, 'prepareFormFields'], ['needs_context' => true]),
  29. new TwigFunction('prepare_form_field', [$this, 'prepareFormField'], ['needs_context' => true]),
  30. new TwigFunction('include_form_field', [$this, 'includeFormField']),
  31. ];
  32. }
  33. public function valueAndLabel($value): array
  34. {
  35. if (!is_array($value)) {
  36. return [];
  37. }
  38. $list = [];
  39. foreach ($value as $key => $label) {
  40. $list[] = ['value' => $key, 'label' => $label];
  41. }
  42. return $list;
  43. }
  44. /**
  45. * Filters form fields for the current parent.
  46. *
  47. * @param array $context
  48. * @param array $fields Form fields
  49. * @param string|null $parent Parent field name if available
  50. * @return array
  51. */
  52. public function prepareFormFields(array $context, $fields, $parent = null): array
  53. {
  54. $list = [];
  55. if (is_iterable($fields)) {
  56. foreach ($fields as $name => $field) {
  57. $field = $this->prepareFormField($context, $field, $name, $parent);
  58. if ($field) {
  59. $list[$field['name']] = $field;
  60. }
  61. }
  62. }
  63. return $list;
  64. }
  65. /**
  66. * Filters field name by changing dot notation into array notation.
  67. *
  68. * @param array $context
  69. * @param array $field Form field
  70. * @param string|int|null $name Field name (defaults to field.name)
  71. * @param string|null $parent Parent field name if available
  72. * @param array|null $options List of options to override
  73. * @return array|null
  74. */
  75. public function prepareFormField(array $context, $field, $name = null, $parent = null, array $options = []): ?array
  76. {
  77. // Make sure that the field is a valid form field type and is not being ignored.
  78. if (empty($field['type']) || ($field['validate']['ignore'] ?? false)) {
  79. return null;
  80. }
  81. // If field has already been prepared, we do not need to do anything.
  82. if (!empty($field['prepared'])) {
  83. return $field;
  84. }
  85. // Check if we have just a list of fields (no name given).
  86. $fieldName = (string)($field['name'] ?? $name);
  87. if (!is_string($name) || $name === '') {
  88. // Look at the field.name and if not set, fall back to the key.
  89. $name = $fieldName;
  90. }
  91. // Make sure that the field has a name.
  92. if ($name === '') {
  93. return null;
  94. }
  95. // Prefix name with the parent name if needed.
  96. if (str_starts_with($name, '.')) {
  97. $plainName = (string)substr($name, 1);
  98. $field['plain_name'] = $plainName;
  99. $name = $parent ? $parent . $name : $plainName;
  100. } elseif (isset($options['key'])) {
  101. $name = str_replace('*', $options['key'], $name);
  102. }
  103. unset($options['key']);
  104. // Set fields as readonly if form is in readonly mode.
  105. /** @var FormInterface $form */
  106. $form = $context['form'] ?? null;
  107. if ($form && method_exists($form, 'isEnabled') && !$form->isEnabled()) {
  108. $options['disabled'] = true;
  109. }
  110. // Loop through options
  111. foreach ($options as $key => $option) {
  112. $field[$key] = $option;
  113. }
  114. // Always set field name.
  115. $field['name'] = $name;
  116. $field['prepared'] = true;
  117. return $field;
  118. }
  119. /**
  120. * @param string $type
  121. * @param string|string[]|null $layouts
  122. * @param string|null $default
  123. * @return string[]
  124. */
  125. public function includeFormField(string $type, $layouts = null, string $default = null): array
  126. {
  127. $list = [];
  128. foreach ((array)$layouts as $layout) {
  129. $list[] = "forms/fields/{$type}/{$layout}-{$type}.html.twig";
  130. }
  131. $list[] = "forms/fields/{$type}/{$type}.html.twig";
  132. if ($default) {
  133. foreach ((array)$layouts as $layout) {
  134. $list[] = "forms/fields/{$default}/{$layout}-{$default}.html.twig";
  135. }
  136. $list[] = "forms/fields/{$default}/{$default}.html.twig";
  137. }
  138. return $list;
  139. }
  140. }