Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
9.09% |
2 / 22 |
CRAP | |
11.76% |
12 / 102 |
| EntityForm | |
0.00% |
0 / 1 |
|
13.04% |
3 / 23 |
1436.08 | |
11.76% |
12 / 102 |
| setOperation | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 3 |
|||
| getBaseFormId | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 4 |
|||
| getFormId | |
100.00% |
1 / 1 |
3 | |
100.00% |
6 / 6 |
|||
| buildForm | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 9 |
|||
| init | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 5 |
|||
| form | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 3 |
|||
| processForm | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
| afterBuild | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 3 |
|||
| actionsElement | |
0.00% |
0 / 1 |
30 | |
0.00% |
0 / 15 |
|||
| actions | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 15 |
|||
| submitForm | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 3 |
|||
| save | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
| buildEntity | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 6 |
|||
| copyFormValuesToEntity | |
100.00% |
1 / 1 |
3 | |
100.00% |
6 / 6 |
|||
| getEntity | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
| setEntity | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
| getEntityFromRouteMatch | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 4 |
|||
| prepareEntity | |
100.00% |
1 / 1 |
1 | |
100.00% |
0 / 0 |
|||
| prepareInvokeAll | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 7 |
|||
| getOperation | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
| setModuleHandler | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
| setEntityManager | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
| setEntityTypeManager | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
| <?php | |
| /** | |
| * @file | |
| * Contains \Drupal\Core\Entity\EntityForm. | |
| */ | |
| namespace Drupal\Core\Entity; | |
| use Drupal\Core\Form\FormBase; | |
| use Drupal\Core\Extension\ModuleHandlerInterface; | |
| use Drupal\Core\Form\FormStateInterface; | |
| use Drupal\Core\Render\Element; | |
| use Drupal\Core\Routing\RouteMatchInterface; | |
| /** | |
| * Base class for entity forms. | |
| * | |
| * @ingroup entity_api | |
| */ | |
| class EntityForm extends FormBase implements EntityFormInterface { | |
| /** | |
| * The name of the current operation. | |
| * | |
| * Subclasses may use this to implement different behaviors depending on its | |
| * value. | |
| * | |
| * @var string | |
| */ | |
| protected $operation; | |
| /** | |
| * The module handler service. | |
| * | |
| * @var \Drupal\Core\Extension\ModuleHandlerInterface | |
| */ | |
| protected $moduleHandler; | |
| /** | |
| * The entity manager. | |
| * | |
| * @var \Drupal\Core\Entity\EntityManagerInterface | |
| * | |
| * @deprecated in Drupal 8.0.0, will be removed before Drupal 9.0.0. | |
| */ | |
| protected $entityManager; | |
| /** | |
| * The entity type manager. | |
| * | |
| * @var \Drupal\Core\Entity\EntityTypeManagerInterface | |
| */ | |
| protected $entityTypeManager; | |
| /** | |
| * The entity being used by this form. | |
| * | |
| * @var \Drupal\Core\Entity\EntityInterface | |
| */ | |
| protected $entity; | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function setOperation($operation) { | |
| // If NULL is passed, do not overwrite the operation. | |
| if ($operation) { | |
| $this->operation = $operation; | |
| } | |
| return $this; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function getBaseFormId() { | |
| // Assign ENTITYTYPE_form as base form ID to invoke corresponding | |
| // hook_form_alter(), #validate, #submit, and #theme callbacks, but only if | |
| // it is different from the actual form ID, since callbacks would be invoked | |
| // twice otherwise. | |
| $base_form_id = $this->entity->getEntityTypeId() . '_form'; | |
| if ($base_form_id == $this->getFormId()) { | |
| $base_form_id = NULL; | |
| } | |
| return $base_form_id; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function getFormId() { | |
| $form_id = $this->entity->getEntityTypeId(); | |
| if ($this->entity->getEntityType()->hasKey('bundle')) { | |
| $form_id .= '_' . $this->entity->bundle(); | |
| } | |
| if ($this->operation != 'default') { | |
| $form_id = $form_id . '_' . $this->operation; | |
| } | |
| return $form_id . '_form'; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function buildForm(array $form, FormStateInterface $form_state) { | |
| // During the initial form build, add this form object to the form state and | |
| // allow for initial preparation before form building and processing. | |
| if (!$form_state->has('entity_form_initialized')) { | |
| $this->init($form_state); | |
| } | |
| // Ensure that edit forms have the correct cacheability metadata so they can | |
| // be cached. | |
| if (!$this->entity->isNew()) { | |
| \Drupal::service('renderer')->addCacheableDependency($form, $this->entity); | |
| } | |
| // Retrieve the form array using the possibly updated entity in form state. | |
| $form = $this->form($form, $form_state); | |
| // Retrieve and add the form actions array. | |
| $actions = $this->actionsElement($form, $form_state); | |
| if (!empty($actions)) { | |
| $form['actions'] = $actions; | |
| } | |
| return $form; | |
| } | |
| /** | |
| * Initialize the form state and the entity before the first form build. | |
| */ | |
| protected function init(FormStateInterface $form_state) { | |
| // Flag that this form has been initialized. | |
| $form_state->set('entity_form_initialized', TRUE); | |
| // Prepare the entity to be presented in the entity form. | |
| $this->prepareEntity(); | |
| // Invoke the prepare form hooks. | |
| $this->prepareInvokeAll('entity_prepare_form', $form_state); | |
| $this->prepareInvokeAll($this->entity->getEntityTypeId() . '_prepare_form', $form_state); | |
| } | |
| /** | |
| * Gets the actual form array to be built. | |
| * | |
| * @see \Drupal\Core\Entity\EntityForm::processForm() | |
| * @see \Drupal\Core\Entity\EntityForm::afterBuild() | |
| */ | |
| public function form(array $form, FormStateInterface $form_state) { | |
| // Add #process and #after_build callbacks. | |
| $form['#process'][] = '::processForm'; | |
| $form['#after_build'][] = '::afterBuild'; | |
| return $form; | |
| } | |
| /** | |
| * Process callback: assigns weights and hides extra fields. | |
| * | |
| * @see \Drupal\Core\Entity\EntityForm::form() | |
| */ | |
| public function processForm($element, FormStateInterface $form_state, $form) { | |
| // If the form is cached, process callbacks may not have a valid reference | |
| // to the entity object, hence we must restore it. | |
| $this->entity = $form_state->getFormObject()->getEntity(); | |
| return $element; | |
| } | |
| /** | |
| * Form element #after_build callback: Updates the entity with submitted data. | |
| * | |
| * Updates the internal $this->entity object with submitted values when the | |
| * form is being rebuilt (e.g. submitted via AJAX), so that subsequent | |
| * processing (e.g. AJAX callbacks) can rely on it. | |
| */ | |
| public function afterBuild(array $element, FormStateInterface $form_state) { | |
| // Rebuild the entity if #after_build is being called as part of a form | |
| // rebuild, i.e. if we are processing input. | |
| if ($form_state->isProcessingInput()) { | |
| $this->entity = $this->buildEntity($element, $form_state); | |
| } | |
| return $element; | |
| } | |
| /** | |
| * Returns the action form element for the current entity form. | |
| */ | |
| protected function actionsElement(array $form, FormStateInterface $form_state) { | |
| $element = $this->actions($form, $form_state); | |
| if (isset($element['delete'])) { | |
| // Move the delete action as last one, unless weights are explicitly | |
| // provided. | |
| $delete = $element['delete']; | |
| unset($element['delete']); | |
| $element['delete'] = $delete; | |
| $element['delete']['#button_type'] = 'danger'; | |
| } | |
| if (isset($element['submit'])) { | |
| // Give the primary submit button a #button_type of primary. | |
| $element['submit']['#button_type'] = 'primary'; | |
| } | |
| $count = 0; | |
| foreach (Element::children($element) as $action) { | |
| $element[$action] += array( | |
| '#weight' => ++$count * 5, | |
| ); | |
| } | |
| if (!empty($element)) { | |
| $element['#type'] = 'actions'; | |
| } | |
| return $element; | |
| } | |
| /** | |
| * Returns an array of supported actions for the current entity form. | |
| * | |
| * @todo Consider introducing a 'preview' action here, since it is used by | |
| * many entity types. | |
| */ | |
| protected function actions(array $form, FormStateInterface $form_state) { | |
| // @todo Consider renaming the action key from submit to save. The impacts | |
| // are hard to predict. For example, see | |
| // \Drupal\language\Element\LanguageConfiguration::processLanguageConfiguration(). | |
| $actions['submit'] = array( | |
| '#type' => 'submit', | |
| '#value' => $this->t('Save'), | |
| '#submit' => array('::submitForm', '::save'), | |
| ); | |
| if (!$this->entity->isNew() && $this->entity->hasLinkTemplate('delete-form')) { | |
| $route_info = $this->entity->urlInfo('delete-form'); | |
| if ($this->getRequest()->query->has('destination')) { | |
| $query = $route_info->getOption('query'); | |
| $query['destination'] = $this->getRequest()->query->get('destination'); | |
| $route_info->setOption('query', $query); | |
| } | |
| $actions['delete'] = array( | |
| '#type' => 'link', | |
| '#title' => $this->t('Delete'), | |
| '#access' => $this->entity->access('delete'), | |
| '#attributes' => array( | |
| 'class' => array('button', 'button--danger'), | |
| ), | |
| ); | |
| $actions['delete']['#url'] = $route_info; | |
| } | |
| return $actions; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| * | |
| * This is the default entity object builder function. It is called before any | |
| * other submit handler to build the new entity object to be used by the | |
| * following submit handlers. At this point of the form workflow the entity is | |
| * validated and the form state can be updated, this way the subsequently | |
| * invoked handlers can retrieve a regular entity object to act on. Generally | |
| * this method should not be overridden unless the entity requires the same | |
| * preparation for two actions, see \Drupal\comment\CommentForm for an example | |
| * with the save and preview actions. | |
| * | |
| * @param array $form | |
| * An associative array containing the structure of the form. | |
| * @param \Drupal\Core\Form\FormStateInterface $form_state | |
| * The current state of the form. | |
| */ | |
| public function submitForm(array &$form, FormStateInterface $form_state) { | |
| // Remove button and internal Form API values from submitted values. | |
| $form_state->cleanValues(); | |
| $this->entity = $this->buildEntity($form, $form_state); | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function save(array $form, FormStateInterface $form_state) { | |
| return $this->entity->save(); | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function buildEntity(array $form, FormStateInterface $form_state) { | |
| $entity = clone $this->entity; | |
| $this->copyFormValuesToEntity($entity, $form, $form_state); | |
| // Invoke all specified builders for copying form values to entity | |
| // properties. | |
| if (isset($form['#entity_builders'])) { | |
| foreach ($form['#entity_builders'] as $function) { | |
| call_user_func_array($function, array($entity->getEntityTypeId(), $entity, &$form, &$form_state)); | |
| } | |
| } | |
| return $entity; | |
| } | |
| /** | |
| * Copies top-level form values to entity properties | |
| * | |
| * This should not change existing entity properties that are not being edited | |
| * by this form. | |
| * | |
| * @param \Drupal\Core\Entity\EntityInterface $entity | |
| * The entity the current form should operate upon. | |
| * @param array $form | |
| * A nested array of form elements comprising the form. | |
| * @param \Drupal\Core\Form\FormStateInterface $form_state | |
| * The current state of the form. | |
| */ | |
| protected function copyFormValuesToEntity(EntityInterface $entity, array $form, FormStateInterface $form_state) { | |
| $values = $form_state->getValues(); | |
| if ($this->entity instanceof EntityWithPluginCollectionInterface) { | |
| // Do not manually update values represented by plugin collections. | |
| $values = array_diff_key($values, $this->entity->getPluginCollections()); | |
| } | |
| // @todo: This relies on a method that only exists for config and content | |
| // entities, in a different way. Consider moving this logic to a config | |
| // entity specific implementation. | |
| foreach ($values as $key => $value) { | |
| $entity->set($key, $value); | |
| } | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function getEntity() { | |
| return $this->entity; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function setEntity(EntityInterface $entity) { | |
| $this->entity = $entity; | |
| return $this; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function getEntityFromRouteMatch(RouteMatchInterface $route_match, $entity_type_id) { | |
| if ($route_match->getRawParameter($entity_type_id) !== NULL) { | |
| $entity = $route_match->getParameter($entity_type_id); | |
| } | |
| else { | |
| $entity = $this->entityManager->getStorage($entity_type_id)->create([]); | |
| } | |
| return $entity; | |
| } | |
| /** | |
| * Prepares the entity object before the form is built first. | |
| */ | |
| protected function prepareEntity() {} | |
| /** | |
| * Invokes the specified prepare hook variant. | |
| * | |
| * @param string $hook | |
| * The hook variant name. | |
| * @param \Drupal\Core\Form\FormStateInterface $form_state | |
| * The current state of the form. | |
| */ | |
| protected function prepareInvokeAll($hook, FormStateInterface $form_state) { | |
| $implementations = $this->moduleHandler->getImplementations($hook); | |
| foreach ($implementations as $module) { | |
| $function = $module . '_' . $hook; | |
| if (function_exists($function)) { | |
| // Ensure we pass an updated translation object and form display at | |
| // each invocation, since they depend on form state which is alterable. | |
| $args = array($this->entity, $this->operation, &$form_state); | |
| call_user_func_array($function, $args); | |
| } | |
| } | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function getOperation() { | |
| return $this->operation; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function setModuleHandler(ModuleHandlerInterface $module_handler) { | |
| $this->moduleHandler = $module_handler; | |
| return $this; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function setEntityManager(EntityManagerInterface $entity_manager) { | |
| $this->entityManager = $entity_manager; | |
| return $this; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function setEntityTypeManager(EntityTypeManagerInterface $entity_type_manager) { | |
| $this->entityTypeManager = $entity_type_manager; | |
| return $this; | |
| } | |
| } |