bcubed-8.x-1.0-beta5/src/Form/ConditionSetForm.php
src/Form/ConditionSetForm.php
<?php
namespace Drupal\bcubed\Form;
use Drupal\Component\Plugin\PluginManagerInterface;
use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Messenger\MessengerInterface;
/**
* The class provides form for condition set.
*
* @package Drupal\bcubed\Form
*/
class ConditionSetForm extends EntityForm {
/**
* Bcubed Event Plugin Manager.
*
* @var \Drupal\bcubed\EventManager
*/
protected $eventManager;
/**
* Bcubed Action Plugin Manager.
*
* @var \Drupal\bcubed\ActionManager
*/
protected $actionManager;
/**
* Bcubed Condition Plugin Manager.
*
* @var \Drupal\bcubed\ConditionManager
*/
protected $conditionManager;
/**
* Messenger.
*
* @var \Drupal\Core\Messenger\MessengerInterface
*/
protected $messenger;
/**
* Constructs a new ConditionSetForm object.
*
* @param \Drupal\Component\Plugin\PluginManagerInterface $event_manager
* Bcubed Event Plugin Manager.
* @param \Drupal\Component\Plugin\PluginManagerInterface $action_manager
* Bcubed Action Plugin Manager.
* @param \Drupal\Component\Plugin\PluginManagerInterface $condition_manager
* Bcubed Condition Plugin Manager.
* @param \Drupal\Core\Messenger\MessengerInterface $messenger
* Messenger.
*/
public function __construct(PluginManagerInterface $event_manager, PluginManagerInterface $action_manager, PluginManagerInterface $condition_manager, MessengerInterface $messenger) {
$this->eventManager = $event_manager;
$this->actionManager = $action_manager;
$this->conditionManager = $condition_manager;
$this->messenger = $messenger;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('plugin.manager.bcubed.event'),
$container->get('plugin.manager.bcubed.action'),
$container->get('plugin.manager.bcubed.condition'),
$container->get('messenger')
);
}
/**
* {@inheritdoc}
*/
public function form(array $form, FormStateInterface $form_state) {
$form = parent::form($form, $form_state);
$form['#tree'] = TRUE;
$condition_set = $this->entity;
$form['label'] = [
'#type' => 'textfield',
'#title' => $this->t('Label'),
'#maxlength' => 255,
'#default_value' => $condition_set->label(),
'#description' => $this->t("Label for the Condition Set."),
'#required' => TRUE,
];
$form['id'] = [
'#type' => 'machine_name',
'#default_value' => $condition_set->id(),
'#machine_name' => [
'exists' => '\Drupal\bcubed\Entity\ConditionSet::load',
],
'#disabled' => !$condition_set->isNew(),
];
$form['description'] = [
'#type' => 'textarea',
'#title' => $this->t('Description'),
'#description' => $this->t('Brief description of this condition set, shown in the condition sets overview.'),
'#default_value' => $condition_set->get('description'),
];
$form['plugins'] = [
'#type' => 'container',
'#prefix' => '<div id="bcubed-plugins-div">',
'#suffix' => '</div>',
];
$this->buildPluginForm($this->eventManager, 'Event', $condition_set, $form, $form_state);
$this->buildPluginForm($this->conditionManager, 'Condition', $condition_set, $form, $form_state);
$this->buildPluginForm($this->actionManager, 'Action', $condition_set, $form, $form_state);
$this->removePluginsWithUnmetDependencies($form, $form_state);
return $form;
}
/**
* Builds a form for the specified plugin.
*/
public function buildPluginForm($pluginManager, $plugin_type, $condition_set, &$form, &$form_state) {
$form['plugins'][$plugin_type] = [
'#type' => 'details',
'#open' => TRUE,
'#title' => $plugin_type . 's',
'#prefix' => '<div id="' . $plugin_type . '-div">',
'#suffix' => '</div>',
];
$current_plugins = $form_state->get('current_' . $plugin_type);
// Fetch plugin definitions.
$plugin_defs = $pluginManager->getDefinitions();
// Build default plugins from config.
if (is_null($current_plugins)) {
$current_plugins = [];
$pluginsettings = [];
$existing_plugins = $condition_set->get(strtolower($plugin_type) . 's');
if (!empty($existing_plugins)) {
foreach ($existing_plugins as $plugin) {
$current_plugins[] = $plugin['id'];
if (!empty($plugin['data'])) {
// Set existing plugin settings.
$pluginsettings[] = $plugin['data'];
}
else {
$pluginsettings[] = FALSE;
}
}
}
$form_state->set('current_' . $plugin_type, $current_plugins);
$form_state->set($plugin_type . '_settings', $pluginsettings);
}
// Add new plugin if a selection has been made.
$selected_plugin = $form_state->getValue(['plugins', $plugin_type, 'add'], 'none');
if (!empty($selected_plugin) && $selected_plugin !== 'none') {
$current_plugins = $form_state->get('current_' . $plugin_type);
$current_plugins[] = $selected_plugin;
$form_state->set('current_' . $plugin_type, $current_plugins);
$pluginsettings = $form_state->get($plugin_type . '_settings');
$pluginsettings[] = FALSE;
$form_state->set($plugin_type . '_settings', $pluginsettings);
$form_state->set('new_' . $plugin_type, count($current_plugins) - 1);
}
$avail_plugins = [];
// Build available plugins based on which definitions
// are unused / support multiple instances.
foreach ($plugin_defs as $plugin_id => $plugin_def) {
if (!in_array($plugin_id, $current_plugins) || (!empty($plugin_def['instances']))) {
$avail_plugins[$plugin_id] = $plugin_def['label'];
}
}
if (!empty($avail_plugins)) {
$form['plugins'][$plugin_type]['add'] = [
'#weight' => 100,
'#type' => 'select',
'#options' => $avail_plugins,
'#empty_option' => 'Add ' . $plugin_type,
'#empty_value' => 'none',
'#ajax' => [
'callback' => [$this, 'ajaxAddPlugin'],
'wrapper' => 'bcubed-plugins-div',
'event' => 'change',
'effect' => 'fade',
'progress' => [
'type' => 'throbber',
],
],
];
}
$pluginsettings = $form_state->get($plugin_type . '_settings');
// Add plugins to form.
for ($i = 0, $size = count($current_plugins); $i < $size; ++$i) {
try {
$plugin_id = $current_plugins[$i];
// Fetch plugin instance.
if ($pluginsettings[$i]) {
// Create pre-configured instance.
$plugin = $pluginManager->createInstance($plugin_id, ['settings' => $pluginsettings[$i]]);
}
else {
// Create instance without configuration.
$plugin = $pluginManager->createInstance($plugin_id);
}
$settings_form = [
'#parents' => ['plugins', $plugin_type, $i],
'#tree' => TRUE,
];
$settings_form = $plugin->settingsForm($settings_form, $form_state);
if (is_null($settings_form)) {
$settings_form = [
'#markup' => '<span>This ' . $plugin_type . ' has no configurable settings</span>',
// Neccessary for obtaining a proper user input array.
'hidden' => ['#type' => 'hidden', '#value' => $i],
];
}
// Fix #states properties of inserted form.
foreach ($settings_form as $itemkey => $item) {
if (isset($item['#states'])) {
foreach ($item['#states'] as $state => $sval) {
foreach ($sval as $key => $value) {
if (preg_match('/name="(.*)"/', $key, $matches)) {
$key = str_replace($matches[1], 'plugins[' . $plugin_type . '][' . $i . '][' . $matches[1] . ']', $key);
$settings_form[$itemkey]['#states'][$state] = [$key => $value];
}
}
}
}
}
$plugin_details = [
'#type' => 'details',
'#title' => $plugin_defs[$plugin_id]['label'],
];
$plugin_details['remove'] = [
'#weight' => 100,
'#type' => 'submit',
'#name' => 'remove_' . $plugin_type . $i,
'#value' => 'Remove ' . $plugin_type,
'#limit_validation_errors' => [],
'#submit' => ['::removePlugin'],
'#ajax' => [
'callback' => [$this, 'ajaxRemovePlugin'],
'wrapper' => 'bcubed-plugins-div',
'effect' => 'fade',
'progress' => [
'type' => 'throbber',
],
],
];
$plugin_details['settings'] = $settings_form;
$form['plugins'][$plugin_type][$i] = $plugin_details;
}
catch (PluginNotFoundException $e) {
// Handle missing plugin.
}
}
return $form;
}
/**
* Removes plugins with unmet dependencies.
*/
public function removePluginsWithUnmetDependencies(&$form, &$form_state) {
// Fetch all existing condition sets.
$existing_condition_sets = $this->entity->loadMultiple();
// Exclude current condition set from list if
// it exists (values will be added back in from formstate)
if (!is_null($this->entity->id())) {
unset($existing_condition_sets[$this->entity->id()]);
}
$event_defs = $this->eventManager->getDefinitions();
$condition_defs = $this->conditionManager->getDefinitions();
$action_defs = $this->actionManager->getDefinitions();
// Build array of active plugin definitions in all other sets.
$other_plugins = [
'event' => [],
'action' => [],
'condition' => [],
];
foreach ($existing_condition_sets as $set) {
$events = $set->get('events');
foreach ($events as $event) {
if (!isset($other_plugins['event'][$event['id']])) {
$other_plugins['event'][$event['id']] = $event_defs[$event['id']];
}
}
$actions = $set->get('actions');
foreach ($actions as $action) {
if (!isset($other_plugins['action'][$action['id']])) {
$other_plugins['action'][$action['id']] = $action_defs[$action['id']];
}
}
$conditions = $set->get('conditions');
foreach ($conditions as $condition) {
if (!isset($other_plugins['condition'][$condition['id']])) {
$other_plugins['condition'][$condition['id']] = $condition_defs[$condition['id']];
}
}
}
// Build array of active plugin definitions in this set.
$current_plugins = [
'event' => [],
'action' => [],
'condition' => [],
];
if (!empty($form_state->get('current_Event'))) {
foreach ($form_state->get('current_Event') as $id) {
if (!isset($current_plugins['event'][$id])) {
$current_plugins['event'][$id] = $event_defs[$id];
}
}
}
if (!empty($form_state->get('current_Action'))) {
foreach ($form_state->get('current_Action') as $id) {
if (!isset($current_plugins['action'][$id])) {
$current_plugins['action'][$id] = $action_defs[$id];
}
}
}
if (!empty($form_state->get('current_Condition'))) {
foreach ($form_state->get('current_Condition') as $id) {
if (!isset($current_plugins['condition'][$id])) {
$current_plugins['condition'][$id] = $condition_defs[$id];
}
}
}
// Build array of active plugin definitions from all sets.
$all_plugins = $other_plugins;
foreach ($current_plugins as $plugin_type => $plugindefs) {
foreach ($current_plugins[$plugin_type] as $id => $def) {
if (!isset($all_plugins[$plugin_type][$id])) {
$all_plugins[$plugin_type][$id] = $def;
}
}
}
// Check available event dependencies.
foreach ($form['plugins']['Event']['add']['#options'] as $id => $value) {
// Skip if there are no dependencies.
if (empty($event_defs[$id]['bcubed_dependencies'])) {
continue;
}
foreach ($event_defs[$id]['bcubed_dependencies'] as $dependency) {
// First check same set for the required plugin.
if ($dependency['same_set'] && !isset($current_plugins[$dependency['plugin_type']][$dependency['plugin_id']])) {
// Remove event.
unset($form['plugins']['Event']['add']['#options'][$id]);
break;
}
// If event is generated,
// the generating plugin must be in another conditionset.
if ($dependency['dependency_type'] == 'generated_by' && !isset($other_plugins[$dependency['plugin_type']][$dependency['plugin_id']])) {
// Remove event.
unset($form['plugins']['Event']['add']['#options'][$id]);
break;
}
// finally, if the event simply requires another plugin from any set,
// check that condition.
if (!isset($all_plugins[$dependency['plugin_type']][$dependency['plugin_id']])) {
// Remove event.
unset($form['plugins']['Event']['add']['#options'][$id]);
break;
}
}
}
// Check available condition dependencies.
foreach ($form['plugins']['Condition']['add']['#options'] as $id => $value) {
// Skip if there are no dependencies.
if (empty($condition_defs[$id]['bcubed_dependencies'])) {
continue;
}
foreach ($condition_defs[$id]['bcubed_dependencies'] as $dependency) {
// Special case for conditions.
if ($dependency['plugin_id'] == '*' && $dependency['dependency_type'] == 'generated_by') {
// Check current set for generated events.
foreach ($current_plugins['event'] as $event) {
if (!empty($event['bcubed_dependencies'])) {
foreach ($event['bcubed_dependencies'] as $event_dependency) {
if ($event_dependency['dependency_type'] == 'generated_by') {
continue 3;
}
}
}
}
// If the above loops did not result in a continue,
// no appropriate events were found.
unset($form['plugins']['Condition']['add']['#options'][$id]);
break;
}
// Check same set for required plugin.
if ($dependency['same_set'] && !isset($current_plugins[$dependency['plugin_type']][$dependency['plugin_id']])) {
// Remove condition.
unset($form['plugins']['Condition']['add']['#options'][$id]);
break;
}
// If the condition simply requires another plugin from any set,
// check that condition.
if (!isset($all_plugins[$dependency['plugin_type']][$dependency['plugin_id']])) {
// Remove condition.
unset($form['plugins']['Condition']['add']['#options'][$id]);
break;
}
}
}
// Check available action dependencies.
foreach ($form['plugins']['Action']['add']['#options'] as $id => $value) {
// Skip if there are no dependencies.
if (empty($action_defs[$id]['bcubed_dependencies'])) {
continue;
}
foreach ($action_defs[$id]['bcubed_dependencies'] as $dependency) {
// First check same set for the required plugin.
if ($dependency['same_set'] && !isset($current_plugins[$dependency['plugin_type']][$dependency['plugin_id']])) {
// Remove action.
unset($form['plugins']['Action']['add']['#options'][$id]);
break;
}
// If the action simply requires another plugin from any set,
// check that condition.
if (!isset($all_plugins[$dependency['plugin_type']][$dependency['plugin_id']])) {
// Remove action.
unset($form['plugins']['Action']['add']['#options'][$id]);
break;
}
}
}
return TRUE;
}
/**
* AJAX add plugin callback.
*/
public function ajaxAddPlugin(array &$form, FormStateInterface &$form_state) {
$plugin_type = $form_state->getTriggeringElement()['#parents'][1];
$form['plugins'][$plugin_type]['add']['#value'] = 'none';
return $form['plugins'];
}
/**
* AJAX remove plugin callback (returns section of previously rebuilt form)
*/
public function ajaxRemovePlugin(array &$form, FormStateInterface &$form_state) {
$plugin_type = $form_state->getTriggeringElement()['#parents'][1];
$pluginsettings = $form_state->get($plugin_type . '_settings');
for ($i = 0, $size = count($pluginsettings); $i < $size; ++$i) {
if ($pluginsettings[$i]) {
foreach ($pluginsettings[$i] as $key => $value) {
$form['plugins'][$plugin_type][$i]['settings'][$key]['#value'] = $value;
}
}
}
return $form['plugins'];
}
/**
* Remove plugin callback.
*/
public function removePlugin(array &$form, FormStateInterface &$form_state) {
$parents = $form_state->getTriggeringElement()['#parents'];
$plugin_type = $parents[1];
$id = $parents[2];
$pluginvalues = $form_state->getUserInput()['plugins'][$plugin_type];
unset($pluginvalues[$id]);
unset($pluginvalues['add']);
$pluginvalues = array_values($pluginvalues);
$current_plugins = $form_state->get('current_' . $plugin_type);
unset($current_plugins[$id]);
$current_plugins = array_values($current_plugins);
$form_state->set($plugin_type . '_settings', $pluginvalues);
$form_state->set('current_' . $plugin_type, $current_plugins);
$form_state->setRebuild();
}
/**
* {@inheritdoc}
*/
protected function copyFormValuesToEntity(EntityInterface $entity, array $form, FormStateInterface $form_state) {
$entity->set('label', $form_state->getValue('label'));
$entity->set('id', $form_state->getValue('id'));
$entity->set('description', $form_state->getValue('description'));
$plugin_types = [
'actions' => 'Action',
'events' => 'Event',
'conditions' => 'Condition',
];
foreach ($plugin_types as $entityproperty => $formproperty) {
$plugins = [];
$current_plugins = $form_state->get('current_' . $formproperty, NULL);
if (!is_null($current_plugins)) {
$pluginvalues = $form_state->getValue(['plugins', $formproperty]);
for ($i = 0, $size = count($current_plugins); $i < $size; ++$i) {
unset($pluginvalues[$i]['remove']);
unset($pluginvalues[$i]['settings']);
$plugins[] = [
'id' => $current_plugins[$i],
'data' => $pluginvalues[$i],
];
}
}
$entity->set($entityproperty, $plugins);
}
}
/**
* {@inheritdoc}
*/
public function save(array $form, FormStateInterface $form_state) {
$condition_set = $this->entity;
// If the condition set is new, set to active.
if ($condition_set->isNew()) {
$condition_set->enable();
}
$status = $condition_set->save();
switch ($status) {
case SAVED_NEW:
$this->messenger()->addMessage($this->t('Created the %label Condition Set.', [
'%label' => $condition_set->label(),
]));
break;
default:
$this->messenger()->addMessage($this->t('Saved the %label Condition Set.', [
'%label' => $condition_set->label(),
]));
}
$form_state->setRedirect('entity.condition_set.collection');
}
}
