View source
<?php
namespace Drupal\feeds;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\HtmlCommand;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Config\Entity\ConfigEntityStorageInterface;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Form\FormState;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Url;
use Drupal\feeds\Ajax\SetHashCommand;
use Drupal\feeds\Plugin\PluginFormFactory;
use Drupal\feeds\Plugin\Type\FeedsPluginInterface;
use Drupal\feeds\Plugin\Type\LockableInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class FeedTypeForm extends EntityForm {
protected $feedTypeStorage;
protected $formFactory;
protected $dateFormatter;
protected $renderer;
public function __construct(ConfigEntityStorageInterface $feed_type_storage, PluginFormFactory $factory, DateFormatterInterface $date_formatter, RendererInterface $renderer) {
$this->feedTypeStorage = $feed_type_storage;
$this->formFactory = $factory;
$this->dateFormatter = $date_formatter;
$this->renderer = $renderer;
}
public static function create(ContainerInterface $container) {
return new static($container
->get('entity_type.manager')
->getStorage('feeds_feed_type'), $container
->get('feeds_plugin_form_factory'), $container
->get('date.formatter'), $container
->get('renderer'));
}
public function form(array $form, FormStateInterface $form_state) {
$form['#tree'] = TRUE;
$values = $form_state
->getValues();
$form['#attached']['library'][] = 'feeds/feeds';
$form['basics'] = [
'#title' => $this
->t('Basic settings'),
'#type' => 'details',
'#open' => $this->entity
->isNew(),
'#tree' => FALSE,
];
$form['basics']['label'] = [
'#type' => 'textfield',
'#title' => $this
->t('Name'),
'#default_value' => $this->entity
->label(),
'#maxlength' => '255',
'#description' => $this
->t('A unique label for this feed type. This label will be displayed in the interface.'),
'#required' => TRUE,
];
$form['basics']['id'] = [
'#type' => 'machine_name',
'#title' => $this
->t('Machine name'),
'#default_value' => $this->entity
->id(),
'#disabled' => !$this->entity
->isNew(),
'#maxlength' => EntityTypeInterface::BUNDLE_MAX_LENGTH,
'#description' => $this
->t('A unique name for this feed type. It must only contain lowercase letters, numbers and underscores.'),
'#machine_name' => [
'exists' => 'Drupal\\feeds\\Entity\\FeedType::load',
'source' => [
'basics',
'label',
],
],
'#required' => TRUE,
];
$form['basics']['description'] = [
'#type' => 'textfield',
'#title' => $this
->t('Description'),
'#description' => $this
->t('A description of this feed type.'),
'#default_value' => $this->entity
->getDescription(),
];
$form['basics']['help'] = [
'#type' => 'textarea',
'#title' => $this
->t('Explanation or submission guidelines'),
'#default_value' => $this->entity
->getHelp(),
'#description' => $this
->t('This text will be displayed at the top of the feed when creating or editing a feed of this type.'),
];
$form['plugin_settings'] = [
'#type' => 'vertical_tabs',
'#weight' => 99,
];
$form['plugin_settings']['#prefix'] = '<div id="feeds-ajax-form-wrapper" class="feeds-feed-type-secondary-settings">';
$form['plugin_settings']['#suffix'] = '</div>';
$form['feed_type_settings'] = [
'#type' => 'details',
'#group' => 'plugin_settings',
'#title' => $this
->t('Settings'),
'#tree' => FALSE,
];
$times = [
900,
1800,
3600,
10800,
21600,
43200,
86400,
259200,
604800,
2419200,
];
$period = array_map(function ($time) {
return $this->dateFormatter
->formatInterval($time);
}, array_combine($times, $times));
foreach ($period as &$p) {
$p = $this
->t('Every @p', [
'@p' => $p,
]);
}
$period = [
FeedTypeInterface::SCHEDULE_NEVER => $this
->t('Off'),
FeedTypeInterface::SCHEDULE_CONTINUOUSLY => $this
->t('As often as possible'),
] + $period;
$cron_required = [
'#type' => 'link',
'#url' => Url::fromUri('https://www.drupal.org/docs/user_guide/en/security-cron.html'),
'#title' => $this
->t('Requires cron to be configured.'),
'#attributes' => [
'target' => '_new',
],
];
$form['feed_type_settings']['import_period'] = [
'#type' => 'select',
'#title' => $this
->t('Import period'),
'#options' => $period,
'#description' => $this
->t('Choose how often a feed should be imported.') . ' ' . $this->renderer
->renderRoot($cron_required),
'#default_value' => $this->entity
->getImportPeriod(),
];
foreach ($this->entity
->getPlugins() as $type => $plugin) {
$options = $this->entity
->getPluginOptionsList($type);
natcasesort($options);
$form[$type . '_wrapper'] = [
'#type' => 'container',
'#attributes' => [
'class' => [
'feeds-plugin-inline',
],
],
];
if (count($options) === 1) {
$form[$type . '_wrapper']['id'] = [
'#type' => 'value',
'#value' => $plugin
->getPluginId(),
'#plugin_type' => $type,
'#parents' => [
$type,
],
];
}
else {
$form[$type . '_wrapper']['id'] = [
'#type' => 'select',
'#title' => $this
->t('@type', [
'@type' => ucfirst($type),
]),
'#options' => $options,
'#default_value' => $plugin
->getPluginId(),
'#ajax' => [
'callback' => '::ajaxCallback',
'wrapper' => 'feeds-ajax-form-wrapper',
'progress' => 'none',
],
'#plugin_type' => $type,
'#parents' => [
$type,
],
];
}
if ($plugin instanceof LockableInterface) {
$form[$type . '_wrapper']['id']['#disabled'] = $plugin
->isLocked();
}
$plugin_state = $this
->createSubFormState($type . '_configuration', $form_state);
if ($this
->pluginHasForm($plugin, 'option')) {
$option_form = $this->formFactory
->createInstance($plugin, 'option');
$form[$type . '_wrapper']['advanced'] = $option_form
->buildConfigurationForm([], $plugin_state);
}
$form[$type . '_wrapper']['advanced']['#prefix'] = '<div id="feeds-plugin-' . $type . '-advanced">';
$form[$type . '_wrapper']['advanced']['#suffix'] = '</div>';
if ($this
->pluginHasForm($plugin, 'configuration')) {
$form_builder = $this->formFactory
->createInstance($plugin, 'configuration');
$plugin_form = $form_builder
->buildConfigurationForm([], $plugin_state);
$form[$type . '_configuration'] = [
'#type' => 'details',
'#group' => 'plugin_settings',
'#title' => $this
->t('@type settings', [
'@type' => ucfirst($type),
]),
];
$form[$type . '_configuration'] += $plugin_form;
}
}
$form_state
->setValue($type . '_configuration', $plugin_state
->getValues());
return parent::form($form, $form_state);
}
protected function actions(array $form, FormStateInterface $form_state) {
$actions = parent::actions($form, $form_state);
if ($this->entity
->isNew()) {
$actions['submit']['#value'] = $this
->t('Save and add mappings');
$actions['submit']['#submit'][] = '::toMapping';
}
else {
$actions['submit']['#value'] = $this
->t('Save feed type');
}
return $actions;
}
protected function getPluginForms() {
$plugins = [];
foreach ($this->entity
->getPlugins() as $type => $plugin) {
if ($this
->pluginHasForm($plugin, 'configuration')) {
$plugins[$type] = $this->formFactory
->createInstance($plugin, 'configuration');
}
}
return $plugins;
}
public function validateForm(array &$form, FormStateInterface $form_state) {
if ($form_state
->getErrors()) {
return;
}
$values =& $form_state
->getValues();
foreach (array_keys($this->entity
->getPlugins()) as $type) {
if (isset($values[$type . '_wrapper']['advanced'])) {
if (!isset($values[$type . '_configuration'])) {
$values[$type . '_configuration'] = [];
}
$values[$type . '_configuration'] += $values[$type . '_wrapper']['advanced'];
}
unset($values[$type . '_wrapper']);
}
foreach ($this
->getPluginForms() as $type => $plugin) {
if (!isset($form[$type . '_configuration'])) {
continue;
}
$plugin_state = $this
->createSubFormState($type . '_configuration', $form_state);
$plugin
->validateConfigurationForm($form[$type . '_configuration'], $plugin_state);
$form_state
->setValue($type . '_configuration', $plugin_state
->getValues());
$this
->moveFormStateErrors($plugin_state, $form_state);
}
parent::validateForm($form, $form_state);
}
public function submitForm(array &$form, FormStateInterface $form_state) {
foreach ($this
->getPluginForms() as $type => $plugin) {
$plugin_state = $this
->createSubFormState($type . '_configuration', $form_state);
$plugin
->submitConfigurationForm($form[$type . '_configuration'], $plugin_state);
$form_state
->setValue($type . '_configuration', $plugin_state
->getValues());
}
parent::submitForm($form, $form_state);
}
public function save(array $form, FormStateInterface $form_state) {
$this->entity
->save();
$form_state
->setRedirect('entity.feeds_feed_type.edit_form', [
'feeds_feed_type' => $this->entity
->id(),
]);
$this
->messenger()
->addStatus($this
->t('Your changes have been saved.'));
}
public function toMapping(array &$form, FormStateInterface $form_state) {
$form_state
->setRedirectUrl($this->entity
->toUrl('mapping'));
}
public function ajaxCallback(array $form, FormStateInterface $form_state) {
$type = $form_state
->getTriggeringElement()['#plugin_type'];
$response = new AjaxResponse();
if (isset($form[$type . '_configuration']['#id'])) {
$hash = ltrim($form[$type . '_configuration']['#id'], '#');
$response
->addCommand(new SetHashCommand($hash));
}
$plugin_settings = $this->renderer
->renderRoot($form['plugin_settings']);
$advanced_settings = $this->renderer
->renderRoot($form[$type . '_wrapper']['advanced']);
$response
->addCommand(new ReplaceCommand('#feeds-ajax-form-wrapper', $plugin_settings));
$response
->addCommand(new ReplaceCommand('#feeds-plugin-' . $type . '-advanced', $advanced_settings));
$attachments = NestedArray::mergeDeep($form['plugin_settings']['#attached'], $form[$type . '_wrapper']['advanced']['#attached']);
$response
->setAttachments($attachments);
$status_messages = [
'#type' => 'status_messages',
];
$output = $this->renderer
->renderRoot($status_messages);
if (!empty($output)) {
$response
->addCommand(new HtmlCommand('.region-messages', $output));
}
return $response;
}
protected function createSubFormState($key, FormStateInterface $form_state) {
return (new FormState())
->setValues($form_state
->getValue($key, []));
}
protected function moveFormStateErrors(FormStateInterface $from, FormStateInterface $to) {
foreach ($from
->getErrors() as $name => $error) {
$to
->setErrorByName($name, $error);
}
}
protected function pluginHasForm(FeedsPluginInterface $plugin, $operation) {
return $this->formFactory
->hasForm($plugin, $operation);
}
}