entityFieldManager = $entity_field_manager; $this->entityTypeManager = $entity_type_manager; $this->moduleHandler = $module_handler; $this->entityType = $entity_type; } /** * {@inheritdoc} */ public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) { return new static( $container->get('entity_field.manager'), $container->get('entity_type.manager'), $container->get('module_handler'), $entity_type ); } /** * {@inheritdoc} */ public function getEntityType() { return $this->entityType; } /** * {@inheritdoc} */ public function getEntityTypeLabels() { $lowercase_label = $this->entityType->getLowercaseLabel(); return [ 'singular' => $lowercase_label, 'plural' => t('@entity_type entities', ['@entity_type' => $lowercase_label]), ]; } /** * {@inheritdoc} */ public function getEntityLabel(EntityInterface $entity) { return $entity->label(); } /** * {@inheritdoc} */ public function getTableFields($bundles) { $definitions = $this->entityFieldManager->getBaseFieldDefinitions($this->entityType->id()); $label_key = $this->entityType->getKey('label'); $label_field_label = t('Label'); if ($label_key && isset($definitions[$label_key])) { $label_field_label = $definitions[$label_key]->getLabel(); } $bundle_key = $this->entityType->getKey('bundle'); $bundle_field_label = t('Type'); if ($bundle_key && isset($definitions[$bundle_key])) { $bundle_field_label = $definitions[$bundle_key]->getLabel(); } $fields = []; $fields['label'] = [ 'type' => 'label', 'label' => $label_field_label, 'weight' => 1, ]; if (count($bundles) > 1) { $fields[$bundle_key] = [ 'type' => 'field', 'label' => $bundle_field_label, 'weight' => 2, 'display_options' => [ 'type' => 'entity_reference_label', 'settings' => ['link' => FALSE], ], ]; } return $fields; } /** * {@inheritdoc} */ public function isTableDragEnabled($element) { $children = Element::children($element); // If there is only one row, disable tabledrag. if (count($children) == 1) { return FALSE; } // If one of the rows is in form context, disable tabledrag. foreach ($children as $key) { if (!empty($element[$key]['form'])) { return FALSE; } } return TRUE; } /** * {@inheritdoc} */ public function entityForm(array $entity_form, FormStateInterface $form_state) { /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */ $entity = $entity_form['#entity']; $form_display = $this->getFormDisplay($entity, $entity_form['#form_mode']); $form_display->buildForm($entity, $entity_form, $form_state); $entity_form['#ief_element_submit'][] = [get_class($this), 'submitCleanFormState']; // Inline entities inherit the parent language. $langcode_key = $this->entityType->getKey('langcode'); if ($langcode_key && isset($entity_form[$langcode_key])) { $entity_form[$langcode_key]['#access'] = FALSE; } if (!empty($entity_form['#translating'])) { // Hide the non-translatable fields. foreach ($entity->getFieldDefinitions() as $field_name => $definition) { if (isset($entity_form[$field_name]) && $field_name != $langcode_key) { $entity_form[$field_name]['#access'] = $definition->isTranslatable(); } } } // Allow other modules to alter the form. $this->moduleHandler->alter('inline_entity_form_entity_form', $entity_form, $form_state); return $entity_form; } /** * {@inheritdoc} */ public function entityFormValidate(array &$entity_form, FormStateInterface $form_state) { // Perform entity validation only if the inline form was submitted, // skipping other requests such as file uploads. $triggering_element = $form_state->getTriggeringElement(); if (!empty($triggering_element['#ief_submit_trigger'])) { /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */ $entity = $entity_form['#entity']; $this->buildEntity($entity_form, $entity, $form_state); $form_display = $this->getFormDisplay($entity, $entity_form['#form_mode']); $form_display->validateFormValues($entity, $entity_form, $form_state); $entity->setValidationRequired(FALSE); foreach($form_state->getErrors() as $name => $message) { // $name may be unknown in $form_state and // $form_state->setErrorByName($name, $message) may suppress the error message. $form_state->setError($triggering_element, $message); } } } /** * {@inheritdoc} */ public function entityFormSubmit(array &$entity_form, FormStateInterface $form_state) { $form_state->cleanValues(); /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */ $entity = $entity_form['#entity']; $this->buildEntity($entity_form, $entity, $form_state); } /** * {@inheritdoc} */ public function save(EntityInterface $entity) { $entity->save(); } /** * {@inheritdoc} */ public function delete($ids, $context) { $storage_handler = $this->entityTypeManager->getStorage($this->entityType->id()); $entities = $storage_handler->loadMultiple($ids); $storage_handler->delete($entities); } /** * Builds an updated entity object based upon the submitted form values. * * @param array $entity_form * The entity form. * @param \Drupal\Core\Entity\ContentEntityInterface $entity * The entity. * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. */ protected function buildEntity(array $entity_form, ContentEntityInterface $entity, FormStateInterface $form_state) { $form_display = $this->getFormDisplay($entity, $entity_form['#form_mode']); $form_display->extractFormValues($entity, $entity_form, $form_state); // Invoke all specified builders for copying form values to entity fields. if (isset($entity_form['#entity_builders'])) { foreach ($entity_form['#entity_builders'] as $function) { call_user_func_array($function, [$entity->getEntityTypeId(), $entity, &$entity_form, &$form_state]); } } } /** * Cleans up the form state for a submitted entity form. * * After field_attach_submit() has run and the form has been closed, the form * state still contains field data in $form_state->get('field'). Unless that * data is removed, the next form with the same #parents (reopened add form, * for example) will contain data (i.e. uploaded files) from the previous form. * * @param $entity_form * The entity form. * @param $form_state * The form state of the parent form. */ public static function submitCleanFormState(&$entity_form, FormStateInterface $form_state) { /** @var \Drupal\Core\Entity\EntityInterface $entity */ $entity = $entity_form['#entity']; $bundle = $entity->bundle(); /** @var \Drupal\Core\Field\FieldDefinitionInterface[] $instances */ $instances = \Drupal::service('entity_field.manager')->getFieldDefinitions($entity_form['#entity_type'], $bundle); foreach ($instances as $instance) { $field_name = $instance->getName(); if (!empty($entity_form[$field_name]['#parents'])) { $parents = $entity_form[$field_name]['#parents']; array_pop($parents); if (!empty($parents)) { $field_state = []; WidgetBase::setWidgetState($parents, $field_name, $form_state, $field_state); } } } } /** * Gets the form display for the given entity. * * @param \Drupal\Core\Entity\ContentEntityInterface $entity * The entity. * @param string $form_mode * The form mode. * * @return \Drupal\Core\Entity\Display\EntityFormDisplayInterface * The form display. */ protected function getFormDisplay(ContentEntityInterface $entity, $form_mode) { return EntityFormDisplay::collectRenderDisplay($entity, $form_mode); } }