View source
<?php
namespace Drupal\opigno_calendar_event\Form;
use Drupal\opigno_calendar_event\CalendarEventExceptionLoggerTrait;
use Drupal\opigno_calendar_event\CalendarEventInterface;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Entity\Display\EntityFormDisplayInterface;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Entity\EntityStorageException;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\StringTranslation\StringTranslationTrait;
class CalendarEventEmbeddedWidget {
use StringTranslationTrait;
use CalendarEventExceptionLoggerTrait;
const ELEMENT_NAME = 'opigno_calendar_event_embedded_widget';
protected $entityTypeManager;
public function __construct(EntityTypeManagerInterface $entity_type_manager) {
$this->entityTypeManager = $entity_type_manager;
}
public function alterForm(array &$form, FormStateInterface $form_state, FieldDefinitionInterface $field_definition, array $calendar_events) {
$widget_state =& $this
->getWidgetState($form, $form_state);
$widget_state['field_definition'] = $field_definition;
$form_object = $form_state
->getFormObject();
$widget_state['original_label'] = $form_object
->getEntity()
->label();
$elements =& $form[static::ELEMENT_NAME];
$elements = [
'#parents' => $this
->getElementParents($form),
'#tree' => TRUE,
];
if (count($calendar_events) > 1) {
$elements += [
'#type' => 'fieldset',
'#title' => $this
->t('Calendar events'),
];
}
foreach (array_values($calendar_events) as $delta => $calendar_event) {
$elements[$delta] = [
'#parents' => $this
->getElementParents($form, $delta),
'#tree' => TRUE,
'#delta' => $delta,
'#entity_builders' => [
[
$this,
'buildEntity',
],
],
];
$item_state =& $this
->getItemState($form, $form_state, $delta);
$item_state['entity'] = $calendar_event;
$form_display = $this
->getItemFormDisplay($form, $form_state, $delta);
$form_display
->buildForm($calendar_event, $elements[$delta], $form_state);
$this
->disableRequired($elements[$delta]);
$this
->attachFieldGroups($elements[$delta], $calendar_event, $form_display);
}
$form['#validate'][] = [
$this,
'validateForm',
];
$form['actions']['submit']['#submit'][] = [
$this,
'submitForm',
];
}
protected function disableRequired(array &$element) {
$element['#required'] = FALSE;
foreach (Element::children($element) as $key) {
$this
->disableRequired($element[$key]);
}
}
protected function attachFieldGroups(array &$element, CalendarEventInterface $entity, EntityFormDisplayInterface $form_display) {
if (!function_exists('field_group_attach_groups')) {
return;
}
$context = [
'entity_type' => $entity
->getEntityTypeId(),
'bundle' => $entity
->bundle(),
'entity' => $entity,
'context' => 'form',
'display_context' => 'form',
'mode' => $form_display
->getMode(),
];
field_group_attach_groups($element, $context);
$element['#pre_render'][] = 'field_group_form_pre_render';
}
public function buildEntity($entity_type_id, CalendarEventInterface $calendar_event, array &$element, FormStateInterface $form_state) {
$widget_state = $this
->getWidgetState($form_state
->getCompleteForm(), $form_state);
$field_definition = $widget_state['field_definition'];
$ref_field_name = $field_definition
->getName();
$form_object = $form_state
->getFormObject();
$referenced_entity = $form_object
->getEntity();
$calendar_event
->set($ref_field_name, $referenced_entity);
$calendar_event_label = $calendar_event
->label();
if (!$calendar_event_label || $widget_state['original_label'] === $calendar_event_label) {
$label = $referenced_entity
->label();
}
else {
$label = $calendar_event_label;
}
$calendar_event
->set('title', $label ?: $this
->t('Calendar event'));
}
public function validateForm(array $form, FormStateInterface $form_state) {
$widget_state =& $this
->getWidgetState($form, $form_state);
$has_errors = $form_state
->hasAnyErrors();
$has_nested_errors = FALSE;
foreach (array_keys($widget_state['items']) as $delta) {
$item_form_object = $this
->getItemFormObject($form, $form_state, $delta);
$item_form_state = $this
->getItemFormState($form, $form_state, $delta);
$calendar_event = $item_form_object
->validateForm($form[static::ELEMENT_NAME][$delta], $item_form_state);
if ($this
->isCalendarEventPopulated($calendar_event)) {
foreach ($item_form_state
->getErrors() as $name => $error) {
$has_nested_errors = TRUE;
$form_state
->setErrorByName($name, $error);
}
}
}
if (!$has_errors && !$has_nested_errors) {
$form_state
->clearErrors();
}
}
public function submitForm(array $form, FormStateInterface $form_state) {
$widget_state = $this
->getWidgetState($form, $form_state);
foreach (array_keys($widget_state['items']) as $delta) {
$item_form_object = $this
->getItemFormObject($form, $form_state, $delta);
$item_form_state = $this
->getItemFormState($form, $form_state, $delta);
$calendar_event = $item_form_object
->buildEntity($form[static::ELEMENT_NAME][$delta], $item_form_state);
try {
if ($this
->isCalendarEventPopulated($calendar_event)) {
$calendar_event
->save();
}
elseif (!$calendar_event
->isNew()) {
$calendar_event
->delete();
}
} catch (EntityStorageException $e) {
$this
->logException($e);
}
}
}
public function &getWidgetState(array $form, FormStateInterface $form_state) {
$storage =& $form_state
->getStorage();
$parents = array_merge([
'field_storage',
'#parents',
], $form['#parents'], [
'#fields',
static::ELEMENT_NAME,
]);
$widget_state =& NestedArray::getValue($storage, $parents, $key_exists);
if (!$key_exists) {
NestedArray::setValue($storage, $parents, []);
$widget_state =& NestedArray::getValue($storage, $parents, $key_exists);
}
return $widget_state;
}
public function &getItemState(array $form, FormStateInterface $form_state, $delta) {
$widget_state =& $this
->getWidgetState($form, $form_state);
if (!isset($widget_state['items'][$delta])) {
$widget_state['items'][$delta] = [];
}
return $widget_state['items'][$delta];
}
protected function getItemFormDisplay(array $form, FormStateInterface $form_state, $delta) {
$widget_state =& $this
->getWidgetState($form, $form_state);
$item_state =& $widget_state['items'][$delta];
if (!isset($item_state['form_display'])) {
$entity = $widget_state['items'][$delta]['entity'];
$widget_state['items'][$delta]['form_display'] = EntityFormDisplay::collectRenderDisplay($entity, 'embedded_widget');
}
return $item_state['form_display'];
}
protected function getItemFormObject(array $form, FormStateInterface $form_state, $delta) {
$widget_state =& $this
->getWidgetState($form, $form_state);
$item_state =& $widget_state['items'][$delta];
if (!isset($item_state['form_object'])) {
$form_object = $this->entityTypeManager
->getFormObject(CalendarEventInterface::ENTITY_TYPE_ID, 'default');
$form_object
->setEntity($item_state['entity']);
$item_form_state = $this
->getItemFormState($form, $form_state, $delta);
$form_object
->setFormDisplay($item_state['form_display'], $item_form_state);
$item_state['form_object'] = $form_object;
}
return $item_state['form_object'];
}
protected function getItemFormState(array $form, FormStateInterface $form_state, $delta) {
$widget_state =& $this
->getWidgetState($form, $form_state);
$item_state =& $widget_state['items'][$delta];
if (!isset($item_state['form_state'])) {
$item_state['form_state'] = clone $form_state;
$item_values = array_intersect_key($form_state
->getValues(), [
static::ELEMENT_NAME => TRUE,
]);
$item_state['form_state']
->setValues($item_values);
}
return $item_state['form_state'];
}
public function &getItemValues(array $form, FormStateInterface $form_state, $delta) {
return NestedArray::getValue($form_state
->getValues(), $this
->getElementParents($form, $delta));
}
protected function getElementParents(array $form, $delta = NULL) {
$parents = $form['#parents'];
$parents[] = static::ELEMENT_NAME;
if (isset($delta)) {
$parents[] = $delta;
}
return $parents;
}
protected function isCalendarEventPopulated(CalendarEventInterface $calendar_event) {
return $calendar_event
->isDisplayed() || !$calendar_event
->getDateItems()
->isEmpty();
}
}