- Issue created by @jurgenhaas
- 🇳🇱Netherlands johnv
I am not sure.
I think you can program a settings form, and add the field. Not sure where the settings are then stored.
Would it be something like this request? ✨ Exceptions that apply to entire bundles ActiveI am also maintainer fo Workflow module,
and there I have learned how to add a widget to a custom form. Perhaps you can take advantage of it:public static function createInstance(WorkflowTransitionInterface $transition) : array { $element = []; $entity_type_manager = \Drupal::service('entity_type.manager'); $entity = $transition->getTargetEntity(); $entity_type_id = $entity->getEntityTypeId(); $entity_bundle = $entity->bundle(); $view_mode = 'default'; $field_name = $transition->getFieldName(); /** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display */ $entity_form_display = $entity_type_manager->getStorage('entity_form_display'); $dummy_form['#parents'] = []; $form_state = new FormState(); $form_display = $entity_form_display->load("$entity_type_id.$entity_bundle.$view_mode"); // $form_state_clone = clone $form_state; // $form_state_clone->set('entity', $entity); // $form_state_clone->set('form_display', $form_display); // $widget_fields = [$field_name]; // foreach ($form_display->getComponents() as $name => $component) { // if (in_array($name, $widget_fields)) { if ($widget = $form_display->getRenderer($field_name)) { $items = $entity->get($field_name); $items->filterEmptyItems(); $element[$field_name] = $widget->form($items, $dummy_form, $form_state); } // } // } return $element; }
- 🇳🇱Netherlands johnv
In the past, I encountered a way to create an Article or Basic page, having PHP in the body text. That might be an alternative.
- 🇳🇱Netherlands johnv
Also, with the Paragraphs module, you can add fields on a per page basis.
- 🇩🇪Germany jurgenhaas Gottmadingen
That approach from the workflow module doesn't work, since I don't have any entity type with an office_hours field. I've carefully reviewed the site's entity types and none could be used as a "dummy" to hold a reference to a field.
In a settings form, something like this would be nice:
$form['officehours'] = [ '#type' => 'office_hours_default', '#title' => $this->t('Office hours'), '#default_value' => [], ];
The, I should receive an array of values when the form gets submitted in the submit handler and should be able to store them in the config entity.
When I try the above code, just nothing appears in the form.
- 🇳🇱Netherlands johnv
Hmm,
in orde to help you, I need your complete, code. But on this level, office_hours acts as any other field.
Ofcourse, you can always add the opening hours as plain text on some page. - 🇩🇪Germany jurgenhaas Gottmadingen
Well, just a regular settings form, as almost all modules bring with them, e.g.
<?php declare(strict_types=1); namespace Drupal\example\Form; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; /** * Provides a APBS Entities form. */ final class ExampleForm extends FormBase { /** * {@inheritdoc} */ public function getFormId(): string { return 'example_example'; } /** * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state): array { $config = \Drupal::configFactory()->get('example.settings'); $form['office_hours'] = [ '#type' => 'office_hours_default', '#title' => $this->t('Office hours'), '#default_value' => $config->get('office_hours'), ]; $form['actions'] = [ '#type' => 'actions', 'submit' => [ '#type' => 'submit', '#value' => $this->t('Send'), ], ]; return $form; } /** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state): void { $config = \Drupal::configFactory()->getEditable('example.settings'); $config->set('office_hours', $form_state->getValue('office_hours')); $config->save(); } }
- 🇳🇱Netherlands johnv
Problem is that your approach uses 'FormElements', not 'FieldWidgets'.
The FormElements are the single time slots, united in the Weekly FieldWidget.Perhaps it is possible to wrap the time slots in a complex Element, like 'checkboxes' is a wrapper around x 'checkbox' elements.
You may borrow code from OfficeHoursWeekWidget::formElement(), which does
$elements[] = ['#type' => 'office_hours_slot', ...]
or from OfficeHoursCOmplextWeekWidget::formElement(), which calles simpler widgets. - 🇩🇪Germany jurgenhaas Gottmadingen
Ah, that might work. Thanks a lot @johnv for pointing that out, I'll give that a try. FYI, a couple of years ago I had a similar requirement with the address field module, where a solution become available at some point as well. So, it should be possible here too, let's see. I'll report back.
- 🇳🇱Netherlands johnv
I have refactored the widget into an element. Now cleaning up code. Please bear with me.
- 🇳🇱Netherlands johnv
As a preliminary version, please drop the attached file in the src/Element directory.
Then :
public function buildForm(array $form, FormStateInterface $form_state) { $form = []; $config = \Drupal::configFactory()->get('example. Settings'); $field_settings = OfficeHoursItem::defaultStorageSettings(); $widget_settings = OfficeHoursWeekWidget::defaultSettings(); $office_hours = $config->get('office_hours') ?? []; $form['office_hours'] = [ '#type' => 'office_hours_table', '#title' => $this->t('Office hours'), '#default_value' => $office_hours, '#field_settings' => $field_settings, '#widget_settings' => $widget_settings, '#field_type' => $week_season_id = 0, ]; $form['actions'] = [ '#type' => 'actions', 'submit' => [ '#type' => 'submit', '#value' => $this->t('Send'), ], ]; return $form; }
and:
public function submitForm(array &$form, FormStateInterface $form_state) { $office_hours = $form_state->getValue(['office_hours']); $config = \Drupal::configFactory()->getEditable('example. Settings'); $config->set('office_hours', $office_hours); $config->save(); }
- 🇩🇪Germany jurgenhaas Gottmadingen
This looks very promising. But I had to make a couple of corrections:
- In the attached file I had to change the class name to
OfficeHoursTableTest
- In the form build code the type should be
office_hours_table_test
Everything else seems to be correct. When I do that, and try to open the form, I'm getting this error:
Error: Attempt to assign property "day_delta" on array in Drupal\office_hours\Element\OfficeHoursBaseSlot::processOfficeHoursSlot() (line 156 of modules/contrib/office_hours/src/Element/OfficeHoursBaseSlot.php).
Note: I'm using the 8.x-1.x dev release for this test.
- In the attached file I had to change the class name to
- 🇩🇪Germany jurgenhaas Gottmadingen
It looks like
OfficeHoursTableTest
provides an array as$element['#value']
instead of anOfficeHoursItem
- Status changed to Needs review
9 months ago 9:34pm 19 April 2024 - Status changed to RTBC
9 months ago 8:08am 22 April 2024 - 🇩🇪Germany jurgenhaas Gottmadingen
This is amazing!!! Thanks @johnv I've tested the latest dev release and that is working exactly as expected. This is outstanding, thank you so much for providing this feature on request.
- 🇳🇱Netherlands johnv
You're welcome :-)
In order to make sure that this functionality won't be lost in the future, a test case is needed.
However, I am not sure how to do that.
Do you know how to create such a test case: create form, save data, check data? - 🇩🇪Germany jurgenhaas Gottmadingen
I'm not an expert in that area, but for our ECA module, a colleague of mine wrote some form submission tests and you can find an example at https://git.drupalcode.org/project/eca/-/blob/2.0.x/modules/form/tests/s...
Maybe that's helpful?
- 🇳🇱Netherlands johnv
Thanks, I will take a look.
Following patch to correct the widget code, which is broken after isolating the Element :-( - Status changed to Fixed
7 months ago 7:55am 29 May 2024 - 🇳🇱Netherlands johnv
I created 📌 Add test for WeekTableElement in a form (not a widget) Active , so this issue can be closed.
- 🇩🇪Germany jurgenhaas Gottmadingen
Thank you so much for taking care of this. Really much appreciated.
Automatically closed - issue fixed for 2 weeks with no activity.