View source
<?php
namespace Drupal\rabbit_hole;
use Drupal\Core\Config\ImmutableConfig;
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\EntityTypeBundleInfo;
use Drupal\Core\Url;
use Drupal\rabbit_hole\Plugin\RabbitHoleBehaviorPlugin\DisplayPage;
use Drupal\rabbit_hole\Plugin\RabbitHoleBehaviorPluginManager;
use Drupal\rabbit_hole\Plugin\RabbitHoleEntityPluginManager;
use Drupal\rabbit_hole\Entity\BehaviorSettings;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Component\Utility\UrlHelper;
class FormManglerService {
use DependencySerializationTrait;
use StringTranslationTrait;
const RABBIT_HOLE_USE_DEFAULT = 'bundle_default';
private $entityTypeManager;
private $rhBehaviorPluginManager;
private $rhEntityPluginManager;
protected $behaviorInvoker;
protected $allBundleInfo;
private $rhBehaviorSettingsManager;
public function __construct(EntityTypeManagerInterface $etm, EntityTypeBundleInfo $etbi, RabbitHoleBehaviorPluginManager $behavior_plugin_manager, RabbitHoleEntityPluginManager $entity_plugin_manager, BehaviorSettingsManager $behavior_settings_manager, TranslationInterface $translation, BehaviorInvokerInterface $behavior_invoker) {
$this->entityTypeManager = $etm;
$this->allBundleInfo = $etbi
->getAllBundleInfo();
$this->rhBehaviorPluginManager = $behavior_plugin_manager;
$this->rhEntityPluginManager = $entity_plugin_manager;
$this->rhBehaviorSettingsManager = $behavior_settings_manager;
$this->stringTranslation = $translation;
$this->behaviorInvoker = $behavior_invoker;
}
public function addRabbitHoleOptionsToGlobalForm(array &$attach, $entity_type, FormStateInterface $form_state, $form_id) {
$entity_type = $this->entityTypeManager
->getStorage($entity_type)
->getEntityType();
$this
->addRabbitHoleOptionsToForm($attach, $entity_type
->id(), NULL, $form_state, $form_id);
}
public function addRabbitHoleOptionsToEntityForm(array &$attach, EntityInterface $entity, FormStateInterface $form_state, $form_id) {
$this
->addRabbitHoleOptionsToForm($attach, $entity
->getEntityType()
->id(), $entity, $form_state, $form_id);
}
private function addRabbitHoleOptionsToForm(array &$attach, $entity_type_id, $entity, FormStateInterface $form_state, $form_id) {
$entity_type = $this->entityTypeManager
->getStorage($entity_type_id)
->getEntityType();
if ($entity === NULL) {
$is_bundle_or_entity_type = TRUE;
}
else {
$is_bundle_or_entity_type = $this
->isEntityBundle($entity);
}
$bundle_settings = NULL;
$bundle = isset($entity) ? $entity
->bundle() : $entity_type_id;
$action = NULL;
$entity_plugin = $this->rhEntityPluginManager
->createInstanceByEntityType($is_bundle_or_entity_type && !empty($entity_type
->getBundleOf()) ? $entity_type
->getBundleOf() : $entity_type
->id());
if ($is_bundle_or_entity_type) {
if ($entity === NULL) {
$bundle_settings = $this->rhBehaviorSettingsManager
->loadBehaviorSettingsAsConfig($entity_type
->id());
}
else {
$bundle_settings = $this->rhBehaviorSettingsManager
->loadBehaviorSettingsAsConfig($entity_type
->id(), $entity
->id());
}
$action = $bundle_settings
->get('action');
}
else {
$submit_location = $entity_plugin
->getFormSubmitHandlerAttachLocations($attach, $form_state);
$this
->attachFormSubmit($attach, $submit_location, [
$this,
'redirectToEntityEditForm',
]);
$bundle_entity_type = $entity_type
->getBundleEntityType() ?: $entity_type
->id();
$bundle_settings = $this->rhBehaviorSettingsManager
->loadBehaviorSettingsAsConfig($bundle_entity_type, $entity
->getEntityType()
->getBundleEntityType() ? $entity
->bundle() : NULL);
if (!$bundle_settings
->get('allow_override')) {
return;
}
$action = isset($entity->rh_action->value) ? $entity->rh_action->value : 'bundle_default';
}
$entity_label = $entity_type
->getLabel();
$bundle_info = isset($this->allBundleInfo[$entity_type
->id()]) ? $this->allBundleInfo[$entity_type
->id()] : NULL;
$bundle_label = NULL !== $bundle_info && NULL !== $bundle_info[$bundle]['label'] ? $bundle_info[$bundle]['label'] : $this
->t('this bundle');
$form['rabbit_hole'] = [
'#type' => 'details',
'#title' => $this
->t('Rabbit Hole settings'),
'#collapsed' => FALSE,
'#collapsible' => TRUE,
'#tree' => FALSE,
'#weight' => 10,
'#group' => $is_bundle_or_entity_type ? 'additional_settings' : 'advanced',
'#attributes' => [
'class' => [
'rabbit-hole-settings-form',
],
],
];
$form['rabbit_hole']['rh_is_bundle'] = [
'#type' => 'hidden',
'#value' => $is_bundle_or_entity_type,
];
$form['rabbit_hole']['rh_entity_type'] = [
'#type' => 'hidden',
'#value' => $entity_type
->id(),
];
if ($is_bundle_or_entity_type) {
$form['rabbit_hole']['rh_override'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Allow these settings to be overridden for individual entities'),
'#default_value' => $bundle_settings
->get('allow_override'),
'#description' => $this
->t('If this is checked, users with the %permission permission will be able to override these settings for individual entities.', [
'%permission' => $this
->t('Administer Rabbit Hole settings for @entity_type', [
'@entity_type' => $entity_label,
]),
]),
];
}
$action_options = $this
->loadBehaviorOptions();
if (!$is_bundle_or_entity_type) {
$action_bundle = $bundle_settings
->get('action');
$action_options = [
self::RABBIT_HOLE_USE_DEFAULT => $this
->t('Global @bundle behavior (@setting)', [
'@bundle' => strtolower($bundle_label),
'@setting' => $action_options[$action_bundle],
]),
] + $action_options;
}
$form['rabbit_hole']['rh_action'] = [
'#type' => 'radios',
'#title' => $this
->t('Behavior'),
'#options' => $action_options,
'#default_value' => $action,
'#description' => $this
->t('What should happen when someone tries to visit an entity page for @bundle?', [
'@bundle' => strtolower($bundle_label),
]),
'#attributes' => [
'class' => [
'rabbit-hole-action-setting',
],
],
];
$this
->populateExtraBehaviorSections($form, $form_state, $form_id, $entity, $is_bundle_or_entity_type, $bundle_settings);
$attach += $form;
$is_global_form = isset($attach['#form_id']) && $attach['#form_id'] === $entity_plugin
->getGlobalConfigFormId();
if ($is_global_form) {
$submit_location = $entity_plugin
->getGlobalFormSubmitHandlerAttachLocations($attach, $form_state);
}
elseif ($is_bundle_or_entity_type) {
$submit_location = $entity_plugin
->getBundleFormSubmitHandlerAttachLocations($attach, $form_state);
}
else {
$submit_location = $entity_plugin
->getFormSubmitHandlerAttachLocations($attach, $form_state);
}
$this
->attachFormSubmit($attach, $submit_location, '_rabbit_hole_general_form_submit');
$attach['rabbit_hole']['rabbit_hole']['redirect']['rh_redirect']['#element_validate'][] = [
'Drupal\\rabbit_hole\\FormManglerService',
'validateFormRedirect',
];
}
public static function validateFormRedirect(array $form, FormStateInterface &$form_state) {
$rh_action = $form_state
->getValue('rh_action');
if ($rh_action == 'page_redirect') {
$redirect = $form_state
->getValue('rh_redirect');
if (!UrlHelper::isExternal($redirect) && $redirect !== '<front>') {
$scheme = parse_url($redirect, PHP_URL_SCHEME);
$accepted_internal_characters = [
'/',
'?',
'#',
'[',
];
if ($scheme === NULL && !in_array(substr($redirect, 0, 1), $accepted_internal_characters)) {
$form_state
->setErrorByName('rh_redirect', t("Internal path '@string' must begin with a '/', '?', '#', or be a token.", [
'@string' => $redirect,
]));
}
}
}
}
public function handleFormSubmit(array $form, FormStateInterface $form_state) {
if ($form_state
->getValue('rh_is_bundle')) {
$entity = NULL;
if (method_exists($form_state
->getFormObject(), 'getEntity')) {
$entity = $form_state
->getFormObject()
->getEntity();
}
$allow_override = $form_state
->getValue('rh_override') ? BehaviorSettings::OVERRIDE_ALLOW : BehaviorSettings::OVERRIDE_DISALLOW;
$this->rhBehaviorSettingsManager
->saveBehaviorSettings([
'action' => $form_state
->getValue('rh_action'),
'allow_override' => $allow_override,
'redirect' => $form_state
->getValue('rh_redirect') ?: '',
'redirect_code' => $form_state
->getValue('rh_redirect_response') ?: BehaviorSettings::REDIRECT_NOT_APPLICABLE,
'redirect_fallback_action' => $form_state
->getvalue('rh_redirect_fallback_action') ?: 'access_denied',
], $form_state
->getValue('rh_entity_type'), isset($entity) ? $entity
->id() : NULL);
}
}
public function redirectToEntityEditForm(array $form, FormStateInterface $form_state) {
$entity = $form_state
->getFormObject()
->getEntity();
$plugin = $this->behaviorInvoker
->getBehaviorPlugin($entity);
if ($plugin !== NULL && !$plugin instanceof DisplayPage) {
$redirect = $form_state
->getRedirect();
if ($redirect instanceof Url && $redirect
->toString() === $entity
->toUrl()
->toString()) {
$form_state
->setRedirectUrl($entity
->toUrl('edit-form'));
}
}
}
protected function loadBehaviorOptions() {
$action_options = [];
foreach ($this->rhBehaviorPluginManager
->getDefinitions() as $id => $def) {
$action_options[$id] = $def['label'];
}
return $action_options;
}
protected function populateExtraBehaviorSections(array &$form, FormStateInterface $form_state, $form_id, EntityInterface $entity = NULL, $entity_is_bundle = FALSE, ImmutableConfig $bundle_settings = NULL) {
foreach ($this->rhBehaviorPluginManager
->getDefinitions() as $id => $def) {
$this->rhBehaviorPluginManager
->createInstance($id)
->settingsForm($form['rabbit_hole'], $form_state, $form_id, $entity, $entity_is_bundle, $bundle_settings);
}
}
protected function attachFormSubmit(&$form, $submit_location, $submit_handler) {
foreach ($submit_location as $location) {
$array_ref =& $form;
if (is_array($location)) {
foreach ($location as $subkey) {
$array_ref =& $array_ref[$subkey];
}
}
else {
$array_ref =& $array_ref[$location];
}
$array_ref[] = $submit_handler;
}
}
protected function isEntityBundle($entity) {
return is_subclass_of($entity, 'Drupal\\Core\\Config\\Entity\\ConfigEntityBundleBase');
}
}