Repository URL to install this package:
|
Version:
2.0.2 ▾
|
<?php
namespace Drupal\custom_forms\Form;
use Drupal\Component\Serialization\Json;
use Drupal\Core\Database\Connection;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Template\Attribute;
use Drupal\Core\Url;
use Drupal\custom_forms\CustomFormItem;
use Drupal\custom_forms\CustomFormItemFactory;
use Drupal\custom_forms\Entity\CustomForm;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Form controller for the custom form entity fields.
*/
class CustomFormFieldListForm extends FormBase {
/**
* @var \Drupal\Core\Database\Connection
* The database connection.
*/
private $connection;
/**
* The entity being used by this form.
*
* @var CustomForm
*/
protected $entity;
/**
* The factory in charge of CRUD operations for custom form items.
*
* @var \Drupal\custom_forms\CustomFormItemFactory
*/
protected $itemFactory;
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('database'),
$container->get('custom_forms.factory.item')
);
}
/**
* {@inheritdoc}
*/
public function __construct(Connection $connection, CustomFormItemFactory $item_factory) {
$this->connection = $connection;
$attributes = \Drupal::request()->attributes;
$this->entity = $attributes->get('custom_form');
$this->itemFactory = $item_factory;
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'custom_form_fields_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['#attributes']['class'][] = 'custom-forms-fields';
$form['#attached']['library'][] = 'custom_forms/admin-style';
$form['#attached']['library'][] = 'core/drupal.dialog.ajax';
$form['#prefix'] = '<div id="custom-form__field-list">';
$form['#suffix'] = '</div>';
$form['#action'] = Url::fromRoute('entity.custom_form.fields_form', ['custom_form' => $this->entity->id()])->toString();
$items = $this->itemFactory->getFormItemsAsTree($this->entity, TRUE);
$table_headers = $this->generateTableHeaders();
$form['items-table'] = [
'#type' => 'table',
'#header' => $table_headers,
'#empty' => $this->t('No fields found for this form.'),
'#attributes' => [
'class' => [
'custom-forms-fields-table',
],
],
'#tabledrag' => [
[
'action' => 'match',
'relationship' => 'parent',
'group' => 'row-pid',
'source' => 'row-id',
'hidden' => TRUE, // Hides the WEIGHT and PARENT columns.
'limit' => FALSE,
],
[
'action' => 'order',
'relationship' => 'sibling',
'group' => 'row-weight'
]
],
];
if (!empty($items)) {
/** @var \Drupal\custom_forms\CustomFormItem $item */
foreach ($items as $item) {
$form['items-table'][$item->id()] = $this->generateTableRow($item);
}
}
$form['actions'] = [
'#type' => 'actions',
];
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Save'),
'#attributes' => [
'class' => [
'button',
'button-action',
'button--primary',
]
],
];
return $form;
}
/**
* {@inheritdoc}
*/
protected function actionsElement(array $form, FormStateInterface $form_state) {
$element = parent::actionsElement($form, $form_state);
// We don't want the ability to delete the form from the fields page.
unset($element['delete']);
return $element;
}
/**
* Generates the table headers for the item table.
*
* @return array
*/
private function generateTableHeaders() {
return [
[
'data' => $this->t('Name'),
'class' => [
'header-field-name',
],
'data-secondary-header' => $this->t('Machine name')
],
[
'data' => $this->t('Visibility'),
'class' => [
'header-visibility',
],
],
$this->t('Type'),
$this->t('Operations'),
$this->t('Weight'),
$this->t('Parent ID'),
];
}
/**
* @param \Drupal\custom_forms\CustomFormItem $item
*
* @return array
*/
private function generateTableRow($item) {
$row = [];
// TableDrag: Mark the table row as draggable.
$row['#attributes']['class'][] = 'draggable';
// TableDrag: Sort the table row according to its existing/configured
// weight.
$row['#weight'] = $item->getWeight();
// Indent item on load.
if (!empty($item->getDepth()) && $item->getDepth() > 0) {
$indentation = [
'#theme' => 'indentation',
'#size' => $item->getDepth(),
];
}
// If the item is a field, give it the class to prevent nesting items under it.
if ($item->getType() === 'field') {
$row['#attributes']['class'][] = 'tabledrag-leaf';
$row['#attributes']['class'][] = 'custom-forms-field';
} else {
$row['#attributes']['class'][] = 'custom-forms-group';
}
// If the item settings specify that it is a root item, give it the class to
// prevent it being nested under other items.
if ((boolean) $item->getSetting('is_root_item')) {
$row['#attributes']['class'][] = 'tabledrag-root';
}
// Add the actual table data.
$label_attributes = new Attribute();
$label_attributes->addClass('label');
if ($item->getType() === 'group') {
$label_attributes->addClass('group-label');
}
$name = [
'#theme' => 'custom_field_list__field_name',
'#label' => $item->getSetting('label'),
'#machine_name' => $item->getMachineName(),
'#label_attributes' => $label_attributes,
];
// Hide the machine name from select fields.
if ($item->isMachineNameHidden()) {
unset($name['#machine_name']);
}
$row['name'] = [
'#markup' => \Drupal::service('renderer')->render($name),
'#prefix' => !empty($indentation) ? \Drupal::service('renderer')->render($indentation) : '',
];
$row['name']['id'] = [
'#type' => 'value',
'#value' => $item->getLangcode(),
'#parents' => ['items-table', $item->id(), 'langcode'],
];
if ($item->getType() === 'field') {
$row['visibility'] = [
'#theme' => 'custom_field_list__field_visibility',
'#visibility' => $item->getSetting('visibility') === 'hidden'? FALSE : TRUE,
];
} else {
$row['visibility'] = [];
}
$row['type'] = [
'#markup' => !empty($item->getPluginDefinition()['label'])? $item->getPluginDefinition()['label'] : '',
];
$field_operations = [
'edit' => [
'title' => $this->t('Settings'),
'url' => Url::fromRoute('custom_form.field_list.item_settings_form', ['custom_form' => $item->getFormId(), 'item' => $item->id()]),
'attributes' => [
'class' => [
'use-ajax'
],
'data-dialog-type' => 'dialog',
'data-dialog-renderer' => 'off_canvas',
'data-dialog-options' => Json::encode([
'width' => '30%'
]),
],
],
];
// Invoke hook for altering field operations.
\Drupal::moduleHandler()->alter('custom_forms_item_operations', $field_operations, $item);
$field_operations['delete'] = [
'title' => $this->t('Delete'),
'url' => Url::fromRoute('custom_form.field_list.delete_item_form', ['custom_form' => $item->getFormId(), 'item' => $item->id()])
];
$row['operations'] = [
'#type' => 'operations',
'#links' => $field_operations
];
// If an item plugin definition has no UI, disable operations.
if (isset($item->getPluginDefinition()['no_ui']) && $item->getPluginDefinition()['no_ui']) {
$row['operations'] = [];
}
$row['weight'] = [
'#type' => 'weight',
'#title' => $this->t('Weight'),
'#title_display' => 'invisible',
'#default_value' => $item->getWeight(),
// Classify the weight element for #tabledrag.
'#attributes' => [
'class' => ['row-weight'],
],
];
$row['parent']['revision'] = [
'#parents' => ['items-table', $item->id(), 'revision'],
'#type' => 'value',
'#value' => $item->getRevision(),
'#attributes' => [
'class' => ['row-id'],
],
];
$row['parent']['id'] = [
'#parents' => ['items-table', $item->id(), 'id'],
'#type' => 'hidden',
'#value' => $item->id(),
'#attributes' => [
'class' => ['row-id'],
],
];
$row['parent']['pid'] = [
'#parents' => ['items-table', $item->id(), 'pid'],
'#type' => 'number',
'#size' => 3,
'#min' => 0,
'#title' => $this->t('Parent ID'),
'#title_display' => 'invisible',
'#default_value' => $item->getParentId(),
'#attributes' => [
'class' => ['row-pid'],
],
];
return $row;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$trigger = $form_state->getTriggeringElement();
$request = \Drupal::request();
if ((isset($trigger['#op']) && $trigger['#op'] === 'ajax_submit') || $request->isXmlHttpRequest()) {
return;
}
$values = $form_state->cleanValues()->getValues();
if (!empty($values['items-table'])) {
// Update weight and parent ID values.
foreach ($values['items-table'] as $id => $item) {
$customFormItem = $this->itemFactory->loadItem($item['id'], $item['revision'], NULL, $item['langcode']);
// If parent ID and weight have not changed, skip this field.
if ($item['pid'] === $customFormItem->getParentId() && $item['weight'] === $customFormItem->getWeight()) {
continue;
}
// We need to make sure that we don't allow items to be nested with a
// field as parent, as that is not supported. This is mainly a fall-
// back in case the javascript fails, or makes some mistakes.
if ($item['pid'] > 0) {
$parent = $this->itemFactory->loadItem($item['pid'], NULL, NULL, $item['langcode']);
// If the parent is a field, we set parent ID to 0 to remove any
// nesting.
if ($parent->getType() === 'field') {
$pid = 0;
} else {
// If not a field, we simply allow the parent value.
$pid = $item['pid'];
}
} else {
$pid = $item['pid'];
}
$query = $this->connection->update('custom_forms__items');
$query->condition('id', $id);
$query->condition('revision', $item['revision']);
$query->condition('langcode', $item['langcode']);
$query->condition('form_revision', $customFormItem->getFormRevisionId());
$query->fields([
'weight' => $item['weight'],
'pid' => $pid
]);
$query->execute();
}
}
}
}