prepopulate-8.x-2.3/src/Populate.php
src/Populate.php
<?php namespace Drupal\prepopulate; use Drupal\Component\Utility\Html; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Render\Element; use Symfony\Component\HttpFoundation\RequestStack; /** * Service to populate fields from URL. * * @package Drupal\prepopulate */ class Populate implements PopulateInterface { /** * The request stack. * * @var \Symfony\Component\HttpFoundation\RequestStack */ protected $request; /** * The entity type manager. * * @var \Drupal\Core\Entity\EntityTypeManagerInterface */ protected $entityTypeManager; /** * The module handler. * * @var \Drupal\Core\Extension\ModuleHandlerInterface */ protected $moduleHandler; /** * The whitelisted element types that can be pre-populated. * * The default list is intentionally limited to not include radios and * checkboxes for security reasons. Site visitors cannot click a link * to an admin page that prepopulates additional permissions or settings * that are un-noticed and unknowingly aggregated to the site. * * @var array */ protected $whitelistedTypes = [ 'container', 'date', 'datelist', 'datetime', 'entity_autocomplete', 'email', 'fieldset', 'inline_entity_form', 'language_select', 'machine_name', 'number', 'path', 'select', 'tel', 'textarea', 'text_format', 'textfield', 'url', ]; /** * Populate constructor. * * @param \Symfony\Component\HttpFoundation\RequestStack $request * The request. * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager * The entity type manager. * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * The module handler. */ public function __construct(RequestStack $request, EntityTypeManagerInterface $entity_type_manager, ModuleHandlerInterface $module_handler) { $this->request = $request; $this->entityTypeManager = $entity_type_manager; $this->moduleHandler = $module_handler; $this->moduleHandler->alter('prepopulate_whitelist', $this->whitelistedTypes); } /** * {@inheritdoc} */ public function populateForm(array &$form, $request_slice = NULL): void { if (is_null($request_slice)) { if ($this->request->getCurrentRequest()->query->has('edit')) { $request_slice = $this->request->getCurrentRequest()->query->all()['edit']; } } if (is_array($request_slice)) { foreach (array_keys($request_slice) as $request_variable) { if (isset($form[$request_variable])) { $element = &$form[$request_variable]; if (isset($element['widget'][0]['value']['#type'])) { $type = $element['widget'][0]['value']['#type']; } elseif (isset($element['widget'][0]['target_id']['#type'])) { $type = $element['widget'][0]['target_id']['#type']; } elseif (isset($element['widget']['#type'])) { $type = $element['widget']['#type']; } elseif (isset($element['#type'])) { $type = $element['#type']; } if (Element::child($request_variable) && !empty($element) && (empty($type) || in_array($type, $this->whitelistedTypes))) { $this->populateForm($element, $request_slice[$request_variable]); } } } } else { // If we don't have a form type, we cannot do anything. if (empty($form['#type'])) { return; } // If we already have a value in the form, don't overwrite it. if (!empty($form['#value']) && is_scalar($form['#value'])) { return; } // If we don't have access, don't alter it. if (isset($form['#access']) && $form['#access'] === FALSE) { return; } $value = Html::escape($request_slice); switch ($form['#type']) { case 'entity_autocomplete': $form['#value'] = $this->formatEntityAutocomplete($value, $form); break; case 'checkbox': $form['#checked'] = $value === 'true'; default: $form['#value'] = $value; break; } } } /** * Check access and properly format an autocomplete string. * * @param string $value * The value. * @param array $element * The form element to populate. * * @return string * The formatted label if entity exists and view label access is allowed. * Otherwise, the value. * * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ protected function formatEntityAutocomplete(string $value, array &$element): string { $entity = $this->entityTypeManager ->getStorage($element['#target_type']) ->load($value); if ($entity && $entity->access('view label')) { return "{$entity->label()} ($value)"; } return $value; } }