You are here

public static function Registrants::processIdentityElement in RNG - Events and Registrations 8

Same name and namespace in other branches
  1. 8.2 src/Element/Registrants.php \Drupal\rng\Element\Registrants::processIdentityElement()
  2. 3.x src/Element/Registrants.php \Drupal\rng\Element\Registrants::processIdentityElement()

Process the registrant element.

Parameters

array $element: An associative array containing the form structure of the element.

\Drupal\Core\Form\FormStateInterface $form_state: The current state of the form.

array $complete_form: An associative array containing the structure of the form.

Return value

array The new form structure for the element.

File

src/Element/Registrants.php, line 84

Class

Registrants
Provides a form element for a registrant and person association.

Namespace

Drupal\rng\Element

Code

public static function processIdentityElement(array &$element, FormStateInterface $form_state, &$complete_form) {
  if (!isset($element['#event'])) {
    throw new \InvalidArgumentException('Element is missing #event property.');
  }
  if (!$element['#event'] instanceof EntityInterface) {
    throw new \InvalidArgumentException('#event for element is not an entity.');
  }
  if (empty($element['#allow_creation']) && empty($element['#allow_reference'])) {
    throw new \InvalidArgumentException('Element cannot create or reference any entities.');
  }
  $utility = new RegistrantsElement($element, $form_state);

  /** @var \Drupal\rng\RegistrantFactory $registrant_factory */
  $registrant_factory = \Drupal::service('rng.registrant.factory');

  /** @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface $bundle_info */
  $bundle_info = \Drupal::service('entity_type.bundle.info');
  $entity_type_manager = \Drupal::entityTypeManager();
  $parents = $element['#parents'];
  $event = $element['#event'];
  $ajax_wrapper_id_root = 'ajax-wrapper-' . implode('-', $parents);
  $element['#tree'] = TRUE;
  $element['#identity_element_root'] = TRUE;
  $element['#prefix'] = '<div id="' . $ajax_wrapper_id_root . '">';
  $element['#suffix'] = '</div>';

  /** @var \Drupal\rng\RegistrantInterface[] $people */
  $people = $element['#value'];
  $values = NestedArray::getValue($form_state
    ->getUserInput(), $parents);
  $for_bundles = $utility
    ->peopleTypeOptions();
  if (isset($values['entities']['for_bundle'])) {
    $for_bundle = $values['entities']['for_bundle'];
  }
  else {

    // Set for bundle if there is only one person type.
    $for_bundle = count($for_bundles) == 1 ? key($for_bundles) : NULL;
  }
  $arity_is_multiple = $utility
    ->getArity() === 'multiple';
  $arity_is_single = !$arity_is_multiple;
  $change_it = $utility
    ->getChangeIt();
  $entity_create_form = $utility
    ->getShowCreateEntitySubform();
  if (!$change_it) {
    $element['for']['#tree'] = TRUE;
    if (count($people) > 0) {
      $people_labels = [];
      foreach ($people as $registrant) {
        $people_labels[] = (string) $registrant
          ->getIdentity()
          ->toLink()
          ->toString();
      }
      if ($arity_is_single) {
        $people_labels = array_slice($people_labels, 0, 1);
      }
      $element['for']['fortext']['#markup'] = (string) t('This registration is for') . ' ' . implode(', ', $people_labels);
      $element['for']['change'] = [
        '#type' => 'submit',
        '#value' => t('Change'),
        '#ajax' => [
          'callback' => [
            static::class,
            'ajaxElementRoot',
          ],
          'wrapper' => $ajax_wrapper_id_root,
        ],
        '#limit_validation_errors' => [],
        '#validate' => [
          [
            static::class,
            'decoyValidator',
          ],
        ],
        '#submit' => [
          [
            static::class,
            'submitChangeDefault',
          ],
        ],
      ];
    }
    else {

      // There are zero registrants.
      $change_it = TRUE;
    }
  }
  $ajax_wrapper_id_people = 'ajax-wrapper-people-' . implode('-', $parents);

  // Drupals' radios element does not pass #executes_submit_callback and
  // #radios to its children radio like it does for #ajax. So we have to
  // create the children radios manually.
  $for_arity_default = $arity_is_multiple ? 'multiple' : 'single';
  $for_arity_options = [
    'single' => t('Single person'),
    'multiple' => t('Multiple people'),
  ];
  $for_arity_any_arity = TRUE;
  $minimum = $element['#registrants_minimum'];
  $maximum = $element['#registrants_maximum'];
  if ($minimum && $minimum > 1 || $maximum && $maximum == 1) {
    $for_arity_any_arity = FALSE;
  }
  $element['for_arity'] = [
    '#type' => 'radios',
    '#title' => t('This registration is for'),
    '#options' => NULL,
    '#access' => $for_arity_any_arity && $change_it,
    '#attributes' => [
      'class' => [
        'for_arity',
      ],
    ],
  ];
  foreach ($for_arity_options as $key => $label) {
    $element['for_arity'][$key]['radio'] = [
      '#type' => 'radio',
      '#title' => $label,
      '#return_value' => $key,
      '#default_value' => $key === $for_arity_default,
      '#parents' => array_merge($parents, [
        'for_arity',
      ]),
      '#ajax' => [
        'callback' => [
          static::class,
          'ajaxElementRoot',
        ],
        'wrapper' => $ajax_wrapper_id_root,
        'progress' => [
          'type' => 'throbber',
          'message' => NULL,
        ],
      ],
      '#limit_validation_errors' => [],
      '#validate' => [
        [
          static::class,
          'decoyValidator',
        ],
      ],
      '#executes_submit_callback' => TRUE,
      '#submit' => [
        [
          static::class,
          'submitArityChange',
        ],
      ],
      '#disabled' => count($people) > 1,
    ];
  }
  $element['people'] = [
    '#prefix' => '<div id="' . $ajax_wrapper_id_people . '">',
    '#suffix' => '</div>',
  ];
  $element['people']['people_list'] = [
    '#type' => 'table',
    '#header' => [
      t('Person'),
      t('Operations'),
    ],
    '#access' => $arity_is_multiple && $change_it,
    '#empty' => t('There are no people yet, add people below.'),
  ];
  foreach ($people as $i => $registrant) {
    $row = [];
    $row[]['#markup'] = $registrant
      ->getIdentity()
      ->toLink()
      ->toString();
    $row[] = [
      // Needs a name else the submission handlers think all buttons are the
      // last button.
      '#name' => 'ajax-submit-' . implode('-', $parents) . '-' . $i,
      '#type' => 'submit',
      '#value' => t('Remove'),
      '#ajax' => [
        'callback' => [
          static::class,
          'ajaxElementRoot',
        ],
        'wrapper' => $ajax_wrapper_id_root,
      ],
      '#limit_validation_errors' => [],
      '#validate' => [
        [
          static::class,
          'decoyValidator',
        ],
      ],
      '#submit' => [
        [
          static::class,
          'submitRemovePerson',
        ],
      ],
      '#identity_element_registrant_row' => $i,
    ];
    $element['people']['people_list'][] = $row;
  }
  $ajax_wrapper_id_entities = 'ajax-wrapper-entities-' . implode('-', $parents);
  $element['entities'] = [
    '#type' => 'details',
    '#access' => $change_it,
    '#prefix' => '<div id="' . $ajax_wrapper_id_entities . '">',
    '#suffix' => '</div>',
    '#open' => TRUE,
    '#tree' => TRUE,
    '#title' => $arity_is_multiple ? t('Add another person') : t('Select person'),
    '#attributes' => [
      'class' => [
        'entities',
      ],
    ],
  ];
  $element['entities']['controls'] = [
    '#type' => 'container',
    '#tree' => TRUE,
    '#attributes' => [
      'class' => [
        'person-controls',
      ],
    ],
  ];
  $element['entities']['controls']['for_bundle'] = [
    '#type' => 'radios',
    '#title' => t('Person type'),
    '#options' => $for_bundles,
    '#default_value' => $for_bundle,
    '#access' => $change_it,
    '#ajax' => [
      'callback' => [
        static::class,
        'ajaxElementRoot',
      ],
      'wrapper' => $ajax_wrapper_id_root,
      'progress' => [
        'type' => 'throbber',
        'message' => NULL,
      ],
    ],
    '#validate' => [
      [
        static::class,
        'decoyValidator',
      ],
    ],
    '#attributes' => [
      'class' => [
        'person-type',
      ],
    ],
    '#parents' => array_merge($parents, [
      'entities',
      'for_bundle',
    ]),
  ];
  $element['entities']['controls']['actions'] = [
    '#type' => 'actions',
    '#tree' => TRUE,
  ];

  // Display a close button if there are people and arity is multiple.
  if ($arity_is_multiple && count($people) > 0) {
    $element['entities']['controls']['actions']['done'] = [
      '#type' => 'submit',
      '#value' => t('Done'),
      '#ajax' => [
        'callback' => [
          static::class,
          'ajaxElementRoot',
        ],
        'wrapper' => $ajax_wrapper_id_root,
      ],
      '#limit_validation_errors' => [],
      '#validate' => [
        [
          static::class,
          'decoyValidator',
        ],
      ],
      '#submit' => [
        [
          static::class,
          'submitClose',
        ],
      ],
    ];
  }
  $element['entities']['person'] = [
    '#type' => 'container',
    '#tree' => TRUE,
    '#attributes' => [
      'class' => [
        'person-container',
      ],
    ],
  ];
  $person_subform =& $element['entities']['person'];
  if ($change_it && isset($for_bundle)) {
    list($person_entity_type_id, $person_bundle) = explode(':', $for_bundle);

    // Registrant
    $person_subform['registrant'] = [
      '#tree' => TRUE,
      '#open' => TRUE,
      '#title' => t('Registrant metadata'),
      '#parents' => array_merge($parents, [
        'entities',
        'person',
        'registrant',
      ]),
    ];
    unset($registrant);
    if ($arity_is_single) {
      $first_registrant = reset($people);
      if ($first_registrant) {
        $registrant = $first_registrant;
      }
    }

    // If no first registrant, then create one.
    if (!isset($registrant)) {
      $registrant = $registrant_factory
        ->createRegistrant([
        'event' => $event,
      ]);
    }
    $display = entity_get_form_display('registrant', $registrant
      ->bundle(), 'default');
    $display
      ->buildForm($registrant, $person_subform['registrant'], $form_state);
    $form_state
      ->set('registrant__form_display', $display);
    $form_state
      ->set('registrant__entity', $registrant);
    if ($for_bundle === 'myself:') {
      $person_subform['myself']['actions'] = [
        '#type' => 'actions',
      ];
      $person_subform['myself']['actions']['add_myself'] = [
        '#type' => 'submit',
        '#value' => $arity_is_single ? t('Select my account') : t('Add my account'),
        '#ajax' => [
          'callback' => [
            static::class,
            'ajaxElementRoot',
          ],
          'wrapper' => $ajax_wrapper_id_root,
        ],
        '#limit_validation_errors' => [
          array_merge($element['#parents'], [
            'entities',
            'person',
            'registrant',
          ]),
          array_merge($element['#parents'], [
            'entities',
            'person',
            'myself',
          ]),
        ],
        '#validate' => [
          [
            static::class,
            'validateMyself',
          ],
        ],
        '#submit' => [
          [
            static::class,
            'submitMyself',
          ],
        ],
      ];
    }
    else {
      $entity_type = $entity_type_manager
        ->getDefinition($person_entity_type_id);
      $entity_bundle_info = $bundle_info
        ->getBundleInfo($person_entity_type_id);
      $bundle_info = $entity_bundle_info[$person_bundle];
      $allow_reference = isset($element['#allow_reference'][$person_entity_type_id]) && in_array($person_bundle, $element['#allow_reference'][$person_entity_type_id]);

      // Existing person
      $person_subform['existing'] = [
        '#type' => 'details',
        '#open' => TRUE,
        '#title' => t('Existing @entity_type', [
          '@entity_type' => $entity_type
            ->getLabel(),
        ]),
        '#identity_element_existing_container' => TRUE,
        '#attributes' => [
          'class' => [
            'existing-container',
          ],
        ],
        '#access' => $allow_reference && $utility
          ->countReferenceableEntities($event, $person_entity_type_id) > 0,
      ];
      $person_subform['existing']['existing_autocomplete'] = [
        '#type' => 'entity_autocomplete',
        '#title' => t('Existing @entity_type', [
          '@entity_type' => $entity_type
            ->getLabel(),
        ]),
        '#target_type' => $person_entity_type_id,
        '#tags' => FALSE,
        '#selection_handler' => 'rng_register',
        '#selection_settings' => [
          'event_entity_type' => $event
            ->getEntityTypeId(),
          'event_entity_id' => $event
            ->id(),
        ],
        '#wrapper_attributes' => [
          'class' => [
            'existing-autocomplete-container',
          ],
        ],
      ];
      if ($entity_type
        ->getBundleEntityType() !== NULL) {

        // This entity type has bundles.
        $person_subform['existing']['existing_autocomplete']['#selection_settings']['target_bundles'] = [
          $person_bundle,
        ];
      }
      if ($arity_is_single) {
        $first_registrant = reset($people);
        if ($first_registrant) {
          $identity = $first_registrant
            ->getIdentity();
          if (isset($identity) && $identity
            ->getEntityTypeId() == $person_entity_type_id) {
            $person_subform['existing']['existing_autocomplete']['#default_value'] = $identity;
          }
        }
      }
      $person_subform['existing']['actions'] = [
        '#type' => 'actions',
      ];
      $person_subform['existing']['actions']['add_existing'] = [
        '#type' => 'submit',
        '#value' => $arity_is_single ? t('Select person') : t('Add person'),
        '#ajax' => [
          'callback' => [
            static::class,
            'ajaxElementRoot',
          ],
          'wrapper' => $ajax_wrapper_id_root,
        ],
        '#limit_validation_errors' => [
          array_merge($element['#parents'], [
            'entities',
            'person',
            'registrant',
          ]),
          array_merge($element['#parents'], [
            'entities',
            'person',
            'existing',
          ]),
        ],
        '#validate' => [
          [
            static::class,
            'validateExisting',
          ],
        ],
        '#submit' => [
          [
            static::class,
            'submitExisting',
          ],
        ],
      ];

      // New entity
      $create = FALSE;
      if (isset($element['#allow_creation'][$person_entity_type_id])) {
        $create = RegistrantsElement::entityCreateAccess($person_entity_type_id, $person_bundle);
      }
      $person_subform['new_person'] = [
        '#type' => 'details',
        '#open' => TRUE,
        '#tree' => TRUE,
        '#title' => t('New @entity_type', [
          '@entity_type' => $entity_type
            ->getLabel(),
        ]),
        '#identity_element_create_container' => TRUE,
        '#access' => $create,
      ];
      if ($entity_create_form) {
        $person_subform['new_person']['newentityform'] = [
          '#access' => $entity_create_form,
          '#tree' => TRUE,
          '#parents' => array_merge($parents, [
            'entities',
            'person',
            'new_person',
            'newentityform',
          ]),
        ];
        $entity_storage = $entity_type_manager
          ->getStorage($person_entity_type_id);
        $new_person_options = [];
        if ($entity_type
          ->getBundleEntityType() !== NULL) {

          // This entity type has bundles.
          $new_person_options[$entity_type
            ->getKey('bundle')] = $person_bundle;
        }
        $new_person = $entity_storage
          ->create($new_person_options);
        $form_mode = 'default';
        if (isset($element['#form_modes'][$person_entity_type_id][$person_bundle])) {
          $form_mode = $element['#form_modes'][$person_entity_type_id][$person_bundle];
        }
        $display = entity_get_form_display($person_entity_type_id, $person_bundle, $form_mode);
        $display
          ->buildForm($new_person, $person_subform['new_person']['newentityform'], $form_state);
        $form_state
          ->set('newentity__form_display', $display);
        $form_state
          ->set('newentity__entity', $new_person);
        $person_subform['new_person']['actions'] = [
          '#type' => 'actions',
          '#weight' => 10000,
        ];
        $person_subform['new_person']['actions']['create'] = [
          '#type' => 'submit',
          '#value' => $arity_is_single ? t('Create and select person') : t('Create and add to registration'),
          '#ajax' => [
            'callback' => [
              static::class,
              'ajaxElementRoot',
            ],
            'wrapper' => $ajax_wrapper_id_root,
          ],
          '#limit_validation_errors' => [
            array_merge($parents, [
              'entities',
              'person',
              'registrant',
            ]),
            array_merge($parents, [
              'entities',
              'person',
              'new_person',
            ]),
          ],
          '#validate' => [
            [
              static::class,
              'validateCreate',
            ],
          ],
          '#submit' => [
            [
              static::class,
              'submitCreate',
            ],
          ],
        ];
        $person_subform['new_person']['actions']['cancel'] = [
          '#type' => 'submit',
          '#value' => t('Cancel'),
          '#ajax' => [
            'callback' => [
              static::class,
              'ajaxElementRoot',
            ],
            'wrapper' => $ajax_wrapper_id_root,
          ],
          '#limit_validation_errors' => [],
          '#toggle_create_entity' => FALSE,
          '#validate' => [
            [
              static::class,
              'decoyValidator',
            ],
          ],
          '#submit' => [
            [
              static::class,
              'submitToggleCreateEntity',
            ],
          ],
        ];
      }
      else {
        $person_subform['new_person']['load_create_form'] = [
          '#type' => 'submit',
          '#value' => t('Create new @label', [
            '@label' => $bundle_info['label'],
          ]),
          '#ajax' => [
            'callback' => [
              static::class,
              'ajaxElementRoot',
            ],
            'wrapper' => $ajax_wrapper_id_root,
          ],
          '#validate' => [
            [
              static::class,
              'decoyValidator',
            ],
          ],
          '#submit' => [
            [
              static::class,
              'submitToggleCreateEntity',
            ],
          ],
          '#toggle_create_entity' => TRUE,
          '#limit_validation_errors' => [],
        ];
      }
    }
  }
  else {

    // There is no subform displayed to the side of "Person type" radios:
    $person_subform['#attributes']['class'][] = 'empty';
    $person_subform['select-person-type'] = [
      '#plain_text' => t('Select person type'),
      '#prefix' => '<div class="message">',
      '#suffix' => '</div>',
    ];
  }
  return $element;
}