Created
March 24, 2016 23:18
-
-
Save andypost/44f3b1bb5147d563a983 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* @file | |
* Contains \Drupal\idevels_proconsort_utility\Plugin\Field\FieldWidget\InlineEntityFormCustom. | |
*/ | |
namespace Drupal\idevels_proconsort_utility\Plugin\Field\FieldWidget; | |
use Drupal\Core\Field\FieldItemListInterface; | |
use Drupal\Core\Form\FormStateInterface; | |
use Drupal\Core\Plugin\ContainerFactoryPluginInterface; | |
use Drupal\Core\Render\Element; | |
use Drupal\inline_entity_form\Plugin\Field\FieldWidget\InlineEntityFormComplex; | |
/** | |
* Custom inline widget. | |
* | |
* @FieldWidget( | |
* id = "inline_entity_form_custom", | |
* label = @Translation("Inline entity form - Complex - custom"), | |
* field_types = { | |
* "entity_reference" | |
* }, | |
* multiple_values = true | |
* ) | |
*/ | |
class InlineEntityFormCustom extends InlineEntityFormComplex implements ContainerFactoryPluginInterface { | |
/** | |
* {@inheritdoc} | |
*/ | |
public static function defaultSettings() { | |
$defaults = parent::defaultSettings(); | |
$defaults += [ | |
'new_button' => '', | |
'existing_button' => '', | |
'delete_dialog' => '', | |
]; | |
return $defaults; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function settingsForm(array $form, FormStateInterface $form_state) { | |
$element = parent::settingsForm($form, $form_state); | |
$states_prefix = 'fields[' . $this->fieldDefinition->getName() . '][settings_edit_form][settings]'; | |
$weight = 1; | |
$element['allow_new']['#weight'] = $weight; | |
$element['new_button'] = [ | |
'#type' => 'textfield', | |
'#title' => $this->t('Title for create new button.'), | |
'#default_value' => $this->getSetting('new_button'), | |
'#states' => [ | |
'visible' => [ | |
':input[name="' . $states_prefix . '[allow_new]"]' => array('checked' => TRUE), | |
], | |
], | |
'#weight' => ++$weight, | |
]; | |
$element['allow_existing']['#weight'] = ++$weight; | |
$element['existing_button'] = [ | |
'#type' => 'textfield', | |
'#title' => $this->t('Title for create existing button.'), | |
'#default_value' => $this->getSetting('existing_button'), | |
'#states' => [ | |
'visible' => [ | |
':input[name="' . $states_prefix . '[allow_existing]"]' => array('checked' => TRUE), | |
], | |
], | |
'#weight' => ++$weight, | |
]; | |
$element['match_operator']['#weight'] = ++$weight; | |
$element['delete_dialog'] = [ | |
'#type' => 'textfield', | |
'#title' => $this->t('Delete dialog text.'), | |
'#default_value' => $this->getSetting('delete_dialog'), | |
'#weight' => ++$weight, | |
]; | |
return $element; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) { | |
if (!$this->canBuildForm($form_state)) { | |
return $element; | |
} | |
$settings = $this->getSettings(); | |
$target_type = $this->getFieldSetting('target_type'); | |
// Get the entity type labels for the UI strings. | |
$labels = $this->getEntityTypeLabels(); | |
// Build a parents array for this element's values in the form. | |
$parents = array_merge($element['#field_parents'], array( | |
$items->getName(), | |
'form', | |
)); | |
// Assign a unique identifier to each IEF widget. | |
// Since $parents can get quite long, sha1() ensures that every id has | |
// a consistent and relatively short length while maintaining uniqueness. | |
$this->setIefId(sha1(implode('-', $parents))); | |
// Get the langcode of the parent entity. | |
$parent_langcode = $items->getParent()->getValue()->language()->getId(); | |
// Determine the wrapper ID for the entire element. | |
$wrapper = 'inline-entity-form-' . $this->getIefId(); | |
$element = array( | |
'#type' => 'fieldset', | |
'#tree' => TRUE, | |
'#description' => NULL, | |
'#prefix' => '<div id="' . $wrapper . '">', | |
'#suffix' => '</div>', | |
'#ief_id' => $this->getIefId(), | |
'#ief_root' => TRUE, | |
) + $element; | |
$element['#attached']['library'][] = 'inline_entity_form/widget'; | |
// Initialize the IEF array in form state. | |
if (!$form_state->has(['inline_entity_form', $this->getIefId(), 'settings'])) { | |
$form_state->set(['inline_entity_form', $this->getIefId(), 'settings'], $this->getFieldSettings()); | |
} | |
if (!$form_state->has(['inline_entity_form', $this->getIefId(), 'instance'])) { | |
$form_state->set(['inline_entity_form', $this->getIefId(), 'instance'], $this->fieldDefinition); | |
} | |
if (!$form_state->has(['inline_entity_form', $this->getIefId(), 'form'])) { | |
$form_state->set(['inline_entity_form', $this->getIefId(), 'form'], NULL); | |
} | |
if (!$form_state->has(['inline_entity_form', $this->getIefId(), 'array_parents'])) { | |
$form_state->set(['inline_entity_form', $this->getIefId(), 'array_parents'], $parents); | |
} | |
$entities = $form_state->get(['inline_entity_form', $this->getIefId(), 'entities']); | |
if (!isset($entities)) { | |
// Load the entities from the $items array and store them in the form | |
// state for further manipulation. | |
$form_state->set(['inline_entity_form', $this->getIefId(), 'entities'], array()); | |
if (count($items)) { | |
foreach ($items as $delta => $item) { | |
if ($item->entity && is_object($item->entity)) { | |
$form_state->set(['inline_entity_form', $this->getIefId(), 'entities', $delta], array( | |
'entity' => $item->entity, | |
'_weight' => $delta, | |
'form' => NULL, | |
'needs_save' => FALSE, | |
)); | |
} | |
} | |
} | |
$entities = $form_state->get(['inline_entity_form', $this->getIefId(), 'entities']); | |
} | |
// Remove any leftover data from removed entity references. | |
foreach ($entities as $key => $value) { | |
if (!isset($value) || !isset($value['entity'])) { | |
unset($entities[$key]); | |
} | |
} | |
// Build the "Multiple value" widget. | |
// TODO - does this belong in #element_validate? | |
$element['#element_validate'][] = [get_class($this), 'updateRowWeights']; | |
// Add the required element marker & validation. | |
if ($element['#required']) { | |
$element['#element_validate'][] = [get_class($this), 'requiredField']; | |
} | |
$element['entities'] = array( | |
'#tree' => TRUE, | |
'#theme' => 'inline_entity_form_entity_table', | |
'#entity_type' => $target_type, | |
); | |
// Get the fields that should be displayed in the table. | |
$target_bundles = $this->getTargetBundles(); | |
$fields = $this->inlineFormHandler->getTableFields($target_bundles); | |
$context = array( | |
'parent_entity_type' => $this->fieldDefinition->getTargetEntityTypeId(), | |
'parent_bundle' => $this->fieldDefinition->getTargetBundle(), | |
'field_name' => $this->fieldDefinition->getName(), | |
'entity_type' => $target_type, | |
'allowed_bundles' => $target_bundles, | |
); | |
$this->moduleHandler->alter('inline_entity_form_table_fields', $fields, $context); | |
$element['entities']['#table_fields'] = $fields; | |
$weight_delta = max(ceil(count($entities) * 1.2), 50); | |
foreach ($entities as $key => $value) { | |
// Data used by theme_inline_entity_form_entity_table(). | |
/** @var \Drupal\Core\Entity\EntityInterface $entity */ | |
$entity = $value['entity']; | |
$element['entities'][$key]['#label'] = $this->inlineFormHandler->getEntityLabel($value['entity']); | |
$element['entities'][$key]['#entity'] = $value['entity']; | |
$element['entities'][$key]['#needs_save'] = $value['needs_save']; | |
// Handle row weights. | |
$element['entities'][$key]['#weight'] = $value['_weight']; | |
// First check to see if this entity should be displayed as a form. | |
if (!empty($value['form'])) { | |
$element['entities'][$key]['title'] = array(); | |
$element['entities'][$key]['delta'] = array( | |
'#type' => 'value', | |
'#value' => $value['_weight'], | |
); | |
// Add the appropriate form. | |
if ($value['form'] == 'edit') { | |
$element['entities'][$key]['form'] = [ | |
'#type' => 'container', | |
'#attributes' => ['class' => ['ief-form', 'ief-form-row']], | |
'inline_entity_form' => $this->getInlineEntityForm( | |
$value['form'], | |
$entity->bundle(), | |
$parent_langcode, | |
$key, | |
array_merge($parents, ['inline_entity_form', 'entities', $key, 'form']), | |
$entity | |
), | |
]; | |
$element['entities'][$key]['form']['inline_entity_form']['#process'] = [ | |
['\Drupal\inline_entity_form\Element\InlineEntityForm', 'processEntityForm'], | |
[get_class($this), 'addIefSubmitCallbacks'], | |
[get_class($this), 'buildEntityFormActions'], | |
]; | |
} | |
elseif ($value['form'] == 'remove') { | |
$element['entities'][$key]['form'] = [ | |
'#type' => 'container', | |
'#attributes' => ['class' => ['ief-form', 'ief-form-row']], | |
// Used by Field API and controller methods to find the relevant | |
// values in $form_state. | |
'#parents' => array_merge($parents, ['entities', $key, 'form']), | |
// Store the entity on the form, later modified in the controller. | |
'#entity' => $entity, | |
// Identifies the IEF widget to which the form belongs. | |
'#ief_id' => $this->getIefId(), | |
// Identifies the table row to which the form belongs. | |
'#ief_row_delta' => $key, | |
]; | |
$this->buildRemoveForm($element['entities'][$key]['form']); | |
} | |
} | |
else { | |
$row = &$element['entities'][$key]; | |
$row['title'] = array(); | |
$row['delta'] = array( | |
'#type' => 'weight', | |
'#delta' => $weight_delta, | |
'#default_value' => $value['_weight'], | |
'#attributes' => array('class' => array('ief-entity-delta')), | |
); | |
// Add an actions container with edit and delete buttons for the entity. | |
$row['actions'] = array( | |
'#type' => 'container', | |
'#attributes' => array('class' => array('ief-entity-operations')), | |
); | |
// Make sure entity_access is not checked for unsaved entities. | |
$entity_id = $entity->id(); | |
if (empty($entity_id) || $entity->access('update')) { | |
$row['actions']['ief_entity_edit'] = array( | |
'#type' => 'submit', | |
'#value' => $this->t('Edit'), | |
'#name' => 'ief-' . $this->getIefId() . '-entity-edit-' . $key, | |
'#limit_validation_errors' => array(), | |
'#ajax' => array( | |
'callback' => 'inline_entity_form_get_element', | |
'wrapper' => $wrapper, | |
), | |
'#submit' => array('inline_entity_form_open_row_form'), | |
'#ief_row_delta' => $key, | |
'#ief_row_form' => 'edit', | |
); | |
} | |
// If 'allow_existing' is on, the default removal operation is unlink | |
// and the access check for deleting happens inside the controller | |
// removeForm() method. | |
if (empty($entity_id) || $settings['allow_existing'] || $entity->access('delete')) { | |
$row['actions']['ief_entity_remove'] = array( | |
'#type' => 'submit', | |
'#value' => $this->t('Remove'), | |
'#name' => 'ief-' . $this->getIefId() . '-entity-remove-' . $key, | |
'#limit_validation_errors' => array(), | |
'#ajax' => array( | |
'callback' => 'inline_entity_form_get_element', | |
'wrapper' => $wrapper, | |
), | |
'#submit' => array('inline_entity_form_open_row_form'), | |
'#ief_row_delta' => $key, | |
'#ief_row_form' => 'remove', | |
); | |
} | |
} | |
} | |
$entities_count = count($entities); | |
$cardinality = $this->fieldDefinition->getFieldStorageDefinition()->getCardinality(); | |
if ($cardinality > 1) { | |
// Add a visual cue of cardinality count. | |
$message = $this->t('You have added @entities_count out of @cardinality_count allowed @label.', array( | |
'@entities_count' => $entities_count, | |
'@cardinality_count' => $cardinality, | |
'@label' => $labels['plural'], | |
)); | |
$element['cardinality_count'] = array( | |
'#markup' => '<div class="ief-cardinality-count">' . $message . '</div>', | |
); | |
} | |
// Do not return the rest of the form if cardinality count has been reached. | |
if ($cardinality > 0 && $entities_count == $cardinality) { | |
return $element; | |
} | |
$target_bundles_count = count($target_bundles); | |
$hide_cancel = FALSE; | |
// If the field is required and empty try to open one of the forms. | |
if (empty($entities) && $this->fieldDefinition->isRequired()) { | |
if ($settings['allow_existing'] && !$settings['allow_new']) { | |
$form_state->set(['inline_entity_form', $this->getIefId(), 'form'], 'ief_add_existing'); | |
$hide_cancel = TRUE; | |
} | |
elseif ($target_bundles_count == 1 && $settings['allow_new'] && !$settings['allow_existing']) { | |
$bundle = reset($target_bundles); | |
// The parent entity type and bundle must not be the same as the inline | |
// entity type and bundle, to prevent recursion. | |
$parent_entity_type = $this->fieldDefinition->getTargetEntityTypeId(); | |
$parent_bundle = $this->fieldDefinition->getTargetBundle(); | |
if ($parent_entity_type != $target_type || $parent_bundle != $bundle) { | |
$form_state->set(['inline_entity_form', $this->getIefId(), 'form'], 'add'); | |
$form_state->set(['inline_entity_form', $this->getIefId(), 'form settings'], array( | |
'bundle' => $bundle, | |
)); | |
$hide_cancel = TRUE; | |
} | |
} | |
} | |
// If no form is open, show buttons that open one. | |
$open_form = $form_state->get(['inline_entity_form', $this->getIefId(), 'form']); | |
if (empty($open_form)) { | |
$element['actions'] = array( | |
'#attributes' => array('class' => array('container-inline')), | |
'#type' => 'container', | |
'#weight' => 100, | |
); | |
// The user is allowed to create an entity of at least one bundle. | |
if ($settings['allow_new'] && $target_bundles_count) { | |
// Let the user select the bundle, if multiple are available. | |
if ($target_bundles_count > 1) { | |
$bundles = array(); | |
foreach ($this->entityTypeBundleInfo->getBundleInfo($target_type) as $bundle_name => $bundle_info) { | |
if (in_array($bundle_name, $target_bundles)) { | |
$bundles[$bundle_name] = $bundle_info['label']; | |
} | |
} | |
$element['actions']['bundle'] = array( | |
'#type' => 'select', | |
'#options' => $bundles, | |
); | |
} | |
else { | |
$element['actions']['bundle'] = array( | |
'#type' => 'value', | |
'#value' => reset($target_bundles), | |
); | |
} | |
$element['actions']['ief_add'] = array( | |
'#type' => 'submit', | |
'#value' => empty($settings['new_button']) ? $this->t('Add new @type_singular', array('@type_singular' => $labels['singular'])) : $settings['new_button'], | |
'#name' => 'ief-' . $this->getIefId() . '-add', | |
'#limit_validation_errors' => array(array_merge($parents, array('actions'))), | |
'#ajax' => array( | |
'callback' => 'inline_entity_form_get_element', | |
'wrapper' => $wrapper, | |
), | |
'#submit' => array('inline_entity_form_open_form'), | |
'#ief_form' => 'add', | |
); | |
} | |
if ($settings['allow_existing']) { | |
$element['actions']['ief_add_existing'] = array( | |
'#type' => 'submit', | |
'#value' => empty($settings['existing_button']) ? $this->t('Add existing @type_singular', array('@type_singular' => $labels['singular'])) : $settings['existing_button'], | |
'#name' => 'ief-' . $this->getIefId() . '-add-existing', | |
'#limit_validation_errors' => array(array_merge($parents, array('actions'))), | |
'#ajax' => array( | |
'callback' => 'inline_entity_form_get_element', | |
'wrapper' => $wrapper, | |
), | |
'#submit' => array('inline_entity_form_open_form'), | |
'#ief_form' => 'ief_add_existing', | |
); | |
} | |
} | |
else { | |
// There's a form open, show it. | |
if ($form_state->get(['inline_entity_form', $this->getIefId(), 'form']) == 'add') { | |
$element['form'] = [ | |
'#type' => 'fieldset', | |
'#attributes' => ['class' => ['ief-form', 'ief-form-bottom']], | |
'inline_entity_form' => $this->getInlineEntityForm( | |
'add', | |
$this->determineBundle($form_state), | |
$parent_langcode, | |
NULL, | |
array_merge($parents, ['inline_entity_form']) | |
) | |
]; | |
$element['form']['inline_entity_form']['#process'] = [ | |
['\Drupal\inline_entity_form\Element\InlineEntityForm', 'processEntityForm'], | |
[get_class($this), 'addIefSubmitCallbacks'], | |
[get_class($this), 'buildEntityFormActions'], | |
]; | |
} | |
elseif ($form_state->get(['inline_entity_form', $this->getIefId(), 'form']) == 'ief_add_existing') { | |
$element['form'] = array( | |
'#type' => 'fieldset', | |
'#attributes' => array('class' => array('ief-form', 'ief-form-bottom')), | |
// Identifies the IEF widget to which the form belongs. | |
'#ief_id' => $this->getIefId(), | |
// Used by Field API and controller methods to find the relevant | |
// values in $form_state. | |
'#parents' => array_merge($parents), | |
// Pass the current entity type. | |
'#entity_type' => $target_type, | |
// Pass the langcode of the parent entity, | |
'#parent_language' => $parent_langcode, | |
// Pass the widget specific labels. | |
'#ief_labels' => $this->getEntityTypeLabels(), | |
); | |
$element['form'] += inline_entity_form_reference_form($element['form'], $form_state); | |
} | |
// Pre-opened forms can't be closed in order to force the user to | |
// add / reference an entity. | |
if ($hide_cancel) { | |
if ($open_form == 'add') { | |
$process_element = &$element['form']['inline_entity_form']; | |
} | |
elseif ($open_form == 'ief_add_existing') { | |
$process_element = &$element['form']; | |
} | |
$process_element['#process'][] = [get_class($this), 'hideCancel']; | |
} | |
// No entities have been added. Remove the outer fieldset to reduce | |
// visual noise caused by having two titles. | |
if (empty($entities)) { | |
$element['#type'] = 'container'; | |
} | |
} | |
return $element; | |
} | |
/** | |
* Builds remove form. | |
* | |
* @param array $form | |
* Form array structure. | |
*/ | |
protected function buildRemoveForm(&$form) { | |
/** @var \Drupal\Core\Entity\EntityInterface $entity */ | |
$entity = $form['#entity']; | |
$entity_id = $entity->id(); | |
$entity_label = $this->inlineFormHandler->getEntityLabel($entity); | |
$labels = $this->getEntityTypeLabels(); | |
$settings = $this->getSettings(); | |
if ($entity_label) { | |
$message = $this->t('Are you sure you want to remove %label?', ['%label' => $entity_label]); | |
} | |
else { | |
$message = $this->t('Are you sure you want to remove this %entity_type?', ['%entity_type' => $labels['singular']]); | |
} | |
$form['message'] = [ | |
'#theme_wrappers' => ['container'], | |
'#markup' => $message, | |
]; | |
if (!empty($entity_id) && $this->getSetting('allow_existing') && $entity->access('delete')) { | |
$form['delete'] = [ | |
'#type' => 'checkbox', | |
'#title' => empty($settings['delete_dialog']) ? $this->t('Delete this @type_singular from the system.', array('@type_singular' => $labels['singular'])) : $settings['delete_dialog'], | |
]; | |
} | |
// Build a deta suffix that's appended to button #name keys for uniqueness. | |
$delta = $form['#ief_id'] . '-' . $form['#ief_row_delta']; | |
// Add actions to the form. | |
$form['actions'] = [ | |
'#type' => 'container', | |
'#weight' => 100, | |
]; | |
$form['actions']['ief_remove_confirm'] = [ | |
'#type' => 'submit', | |
'#value' => $this->t('Remove'), | |
'#name' => 'ief-remove-confirm-' . $delta, | |
'#limit_validation_errors' => [$form['#parents']], | |
'#ajax' => [ | |
'callback' => 'inline_entity_form_get_element', | |
'wrapper' => 'inline-entity-form-' . $form['#ief_id'], | |
], | |
'#submit' => [[get_class($this), 'submitConfirmRemove']], | |
'#ief_row_delta' => $form['#ief_row_delta'], | |
]; | |
$form['actions']['ief_remove_cancel'] = [ | |
'#type' => 'submit', | |
'#value' => $this->t('Cancel'), | |
'#name' => 'ief-remove-cancel-' . $delta, | |
'#limit_validation_errors' => [], | |
'#ajax' => [ | |
'callback' => 'inline_entity_form_get_element', | |
'wrapper' => 'inline-entity-form-' . $form['#ief_id'], | |
], | |
'#submit' => [[get_class($this), 'submitCloseRow']], | |
'#ief_row_delta' => $form['#ief_row_delta'], | |
]; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment