Exemplo n.º 1
1
 /**
  * Button #submit callback: Triggers submission of element forms.
  *
  * @param array $form
  *   The form.
  * @param \Drupal\Core\Form\FormStateInterface $form_state
  *   The form state.
  */
 public static function trigger($form, FormStateInterface $form_state)
 {
     $triggered_element = $form_state->getTriggeringElement();
     if (!empty($triggered_element['#ief_submit_trigger_all'])) {
         // The parent form was submitted, process all IEFs and their children.
         static::doSubmit($form, $form_state);
     } else {
         // A specific element was submitted, process it and all of its children.
         $array_parents = $triggered_element['#array_parents'];
         $array_parents = array_slice($array_parents, 0, -2);
         $element = NestedArray::getValue($form, $array_parents);
         static::doSubmit($element, $form_state);
     }
 }
Exemplo n.º 2
1
 /**
  * Ajax callback to render a sample of the input date format.
  *
  * @param array $form
  *   Form API array structure.
  * @param \Drupal\Core\Form\FormStateInterface $form_state
  *   Form state information.
  *
  * @return AjaxResponse
  *   Ajax response with the rendered sample date using the given format. If
  *   the given format cannot be identified or was empty, the response will
  *   be empty as well.
  */
 public static function ajaxSample(array $form, FormStateInterface $form_state)
 {
     $response = new AjaxResponse();
     $format_value = NestedArray::getValue($form_state->getValues(), $form_state->getTriggeringElement()['#array_parents']);
     if (!empty($format_value)) {
         // Format the date with a custom date format with the given pattern.
         // The object is not instantiated in an Ajax context, so $this->t()
         // cannot be used here.
         $format = t('Displayed as %date_format', array('%date_format' => \Drupal::service('date.formatter')->format(REQUEST_TIME, 'custom', $format_value)));
         // Return a command instead of a string, since the Ajax framework
         // automatically prepends an additional empty DIV element for a string,
         // which breaks the layout.
         $response->addCommand(new ReplaceCommand('#edit-date-format-suffix', '<small id="edit-date-format-suffix">' . $format . '</small>'));
     }
     return $response;
 }
 /**
  * Implements #element_validate callback for self::fieldSettingsForm().
  */
 public static function fieldSettingsFormValidate(array $element, FormStateInterface $form_state)
 {
     $add_more_button_form_parents = array_merge($element['#array_parents'], ['line_items', 'add_more', 'add']);
     // Only set the field settings as a value when it is not the "Add more"
     // button that has been clicked.
     $triggering_element = $form_state->getTriggeringElement();
     if ($triggering_element['#array_parents'] != $add_more_button_form_parents) {
         $values = $form_state->getValues();
         $values = NestedArray::getValue($values, $element['#array_parents']);
         $line_items_data = [];
         foreach (PaymentLineItemsInput::getLineItems($element['line_items'], $form_state) as $line_item) {
             $line_items_data[] = ['plugin_id' => $line_item->getPluginId(), 'plugin_configuration' => $line_item->getConfiguration()];
         }
         $value = ['currency_code' => $values['currency_code'], 'line_items_data' => $line_items_data];
         $form_state->setValueForElement($element, $value);
     }
 }
 /**
  * Ajax callback to remove a field collection from a multi-valued field.
  *
  * @param array $form
  * @param \Drupal\Core\Form\FormStateInterface $form_state
  *
  * @return \Drupal\Core\Ajax\AjaxResponse
  *   An AjaxResponse object.
  */
 function ajaxRemove(array $form, FormStateInterface &$form_state)
 {
     // Process user input. $form and $form_state are modified in the process.
     //\Drupal::formBuilder()->processForm($form['#form_id'], $form, $form_state);
     // Retrieve the element to be rendered.
     $trigger = $form_state->getTriggeringElement();
     $form_parents = explode('/', $trigger['#ajax']['options']['query']['element_parents']);
     $address = array_slice($form_parents, 0, -1);
     $form = NestedArray::getValue($form, $address);
     $status_messages = array('#theme' => 'status_messages');
     $renderer = \Drupal::service('renderer');
     $form['#prefix'] = empty($form['#prefix']) ? $renderer->render($status_messages) : $form['#prefix'] . $renderer->render($status_messages);
     $output = $renderer->render($form);
     drupal_process_attached($form);
     // TODO: Preserve javascript.  See https://www.drupal.org/node/2502743 .
     $response = new AjaxResponse();
     return $response->addCommand(new ReplaceCommand(NULL, $output));
 }
Exemplo n.º 5
0
 /**
  * {@inheritdoc}
  */
 public function buildForm(array $form, FormStateInterface $form_state, FilterFormat $filter_format = NULL)
 {
     // Add AJAX support.
     $form['#prefix'] = '<div id="video-embed-dialog-form">';
     $form['#suffix'] = '</div>';
     // Ensure relevant dialog libraries are attached.
     $form['#attached']['library'][] = 'editor/drupal.editor.dialog';
     // Simple URL field and submit button for video URL.
     $form['video_url'] = ['#type' => 'textfield', '#title' => $this->t('Video URL'), '#required' => TRUE, '#default_value' => $this->getUserInput($form_state, 'video_url')];
     // If no settings are found, use the defaults configured in the filter
     // formats interface.
     $settings = $this->getUserInput($form_state, 'settings');
     if (empty($settings) && ($editor = Editor::load($filter_format->id()))) {
         $editor_settings = $editor->getSettings();
         $plugin_settings = NestedArray::getValue($editor_settings, ['plugins', 'video_embed', 'defaults', 'children']);
         $settings = $plugin_settings ? $plugin_settings : [];
     }
     // Create a settings form from the existing video formatter.
     $form['settings'] = Video::mockInstance($settings)->settingsForm([], new FormState());
     $form['settings']['#type'] = 'fieldset';
     $form['settings']['#title'] = $this->t('Settings');
     $form['actions'] = ['#type' => 'actions'];
     $form['actions']['save_modal'] = ['#type' => 'submit', '#value' => $this->t('Save'), '#submit' => [], '#ajax' => ['callback' => '::ajaxSubmit', 'event' => 'click', 'wrapper' => 'video-embed-dialog-form']];
     return $form;
 }
 public function validateForm(array &$element, array &$form_state, \Payment $payment)
 {
     $values = \Drupal\Component\Utility\NestedArray::getValue($form_state['values'], $element['#parents']);
     if (!empty($values['send_transfer_form'])) {
         $payment->method_data['send_transfer_form'] = $values['send_transfer_form'];
     }
 }
Exemplo n.º 7
0
 /**
  * {@inheritdoc}
  */
 public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property)
 {
     $new_value = $value;
     if (is_array($value)) {
         if (!$value) {
             throw new MigrateException('Can not lookup without a value.');
         }
     } else {
         $new_value = array($value);
     }
     $new_value = NestedArray::getValue($this->configuration['map'], $new_value, $key_exists);
     if (!$key_exists) {
         if (array_key_exists('default_value', $this->configuration)) {
             if (!empty($this->configuration['bypass'])) {
                 throw new MigrateException('Setting both default_value and bypass is invalid.');
             }
             return $this->configuration['default_value'];
         }
         if (empty($this->configuration['bypass'])) {
             throw new MigrateSkipRowException();
         } else {
             return $value;
         }
     }
     return $new_value;
 }
 /**
  * {@inheritdoc}
  */
 public function settingsForm(array $form, FormStateInterface $form_state, Editor $editor)
 {
     $editor_settings = $editor->getSettings();
     $plugin_settings = NestedArray::getValue($editor_settings, ['plugins', 'video_embed', 'defaults', 'children']);
     $settings = $plugin_settings ?: [];
     $form['defaults'] = ['#title' => $this->t('Default Settings'), '#type' => 'fieldset', '#tree' => TRUE, 'children' => Video::mockInstance($settings)->settingsForm([], new FormState())];
     return $form;
 }
 public function validateForm(array &$element, array &$form_state, \Payment $payment)
 {
     $values = \Drupal\Component\Utility\NestedArray::getValue($form_state['values'], $element['#parents']);
     $this->validateValues($element, $values);
     // Merge in validated fields.
     foreach (array('issuer', 'credit_card_number', 'secure_code', 'expiry_date') as $key) {
         $payment->method_data[$key] = $values[$key];
     }
 }
 /**
  * Listener for migration imports.
  */
 public function onMigrateImport(MigrateImportEvent $event)
 {
     $migration = $event->getMigration();
     $configuration = $migration->getDestinationConfiguration();
     $entity_types = NestedArray::getValue($configuration, ['content_translation_update_definitions']);
     if ($entity_types) {
         $entity_types = array_intersect_key($this->entityManager->getDefinitions(), array_flip($entity_types));
         $this->updateDefinitions($entity_types);
     }
 }
 /**
  * {@inheritdoc}
  */
 public function massageFormValues(array $values, array $form, FormStateInterface $form_state)
 {
     $massaged_values = [];
     foreach ($values as $delta => $item_values) {
         $element = NestedArray::getValue($form, array_slice($item_values['array_parents'], count($form['#array_parents'])));
         $plugin_selector = static::getPluginSelector($form_state, $element);
         $plugin_selector->submitSelectorForm($element['plugin_selector'], $form_state);
         $massaged_values[$delta] = ['plugin_instance' => $plugin_selector->getSelectedPlugin()];
     }
     return $massaged_values;
 }
Exemplo n.º 12
0
 /**
  * {@inheritdoc}
  */
 public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property)
 {
     if (!is_array($value)) {
         throw new MigrateException('Input should be an array.');
     }
     $new_value = NestedArray::getValue($value, $this->configuration['index'], $key_exists);
     if (!$key_exists) {
         throw new MigrateException('Array index missing, extraction failed.');
     }
     return $new_value;
 }
 /**
  * Processes AJAX file uploads and deletions.
  *
  * @param \Symfony\Component\HttpFoundation\Request $request
  *   The current request object.
  *
  * @return \Drupal\Core\Ajax\AjaxResponse
  *   An AjaxResponse object.
  */
 public function upload(Request $request)
 {
     $form_parents = explode('/', $request->query->get('element_parents'));
     $form_build_id = $request->query->get('form_build_id');
     $request_form_build_id = $request->request->get('form_build_id');
     if (empty($request_form_build_id) || $form_build_id !== $request_form_build_id) {
         // Invalid request.
         drupal_set_message(t('An unrecoverable error occurred. The uploaded file likely exceeded the maximum file size (@size) that this server supports.', array('@size' => format_size(file_upload_max_size()))), 'error');
         $response = new AjaxResponse();
         $status_messages = array('#theme' => 'status_messages');
         return $response->addCommand(new ReplaceCommand(NULL, drupal_render($status_messages)));
     }
     try {
         /** @var $ajaxForm \Drupal\system\FileAjaxForm */
         $ajaxForm = $this->getForm($request);
         $form = $ajaxForm->getForm();
         $form_state = $ajaxForm->getFormState();
         $commands = $ajaxForm->getCommands();
     } catch (HttpExceptionInterface $e) {
         // Invalid form_build_id.
         drupal_set_message(t('An unrecoverable error occurred. Use of this form has expired. Try reloading the page and submitting again.'), 'error');
         $response = new AjaxResponse();
         $status_messages = array('#theme' => 'status_messages');
         return $response->addCommand(new ReplaceCommand(NULL, drupal_render($status_messages)));
     }
     // Get the current element and count the number of files.
     $current_element = NestedArray::getValue($form, $form_parents);
     $current_file_count = isset($current_element['#file_upload_delta']) ? $current_element['#file_upload_delta'] : 0;
     // Process user input. $form and $form_state are modified in the process.
     drupal_process_form($form['#form_id'], $form, $form_state);
     // Retrieve the element to be rendered.
     $form = NestedArray::getValue($form, $form_parents);
     // Add the special Ajax class if a new file was added.
     if (isset($form['#file_upload_delta']) && $current_file_count < $form['#file_upload_delta']) {
         $form[$current_file_count]['#attributes']['class'][] = 'ajax-new-content';
     } else {
         $form['#suffix'] .= '<span class="ajax-new-content"></span>';
     }
     $status_messages = array('#theme' => 'status_messages');
     $form['#prefix'] .= drupal_render($status_messages);
     $output = drupal_render($form);
     drupal_process_attached($form);
     $js = _drupal_add_js();
     $settings = drupal_merge_js_settings($js['settings']['data']);
     $response = new AjaxResponse();
     foreach ($commands as $command) {
         $response->addCommand($command, TRUE);
     }
     return $response->addCommand(new ReplaceCommand(NULL, $output, $settings));
 }
Exemplo n.º 14
0
 /**
  * Global #process callback for form elements.
  *
  * @param array $element
  *   The element render array.
  * @param \Drupal\Core\Form\FormStateInterface $form_state
  *   The current state of the form.
  * @param array $complete_form
  *   The complete form structure.
  *
  * @return array
  *   The altered element array.
  *
  * @see \Drupal\bootstrap\Plugin\Alter\ElementInfo::alter
  */
 public static function process(array $element, FormStateInterface $form_state, array &$complete_form)
 {
     if (!empty($element['#bootstrap_ignore_process'])) {
         return $element;
     }
     static $theme;
     if (!isset($theme)) {
         $theme = Bootstrap::getTheme();
     }
     $e = Element::create($element, $form_state);
     // Add "form-inline" class.
     if ($e->hasClass('container-inline')) {
         $e->replaceClass('container-inline', 'form-inline');
     }
     if ($e->isType(['color', 'date', 'number', 'password', 'password_confirm', 'range', 'tel', 'weight'])) {
         $e->addClass('form-inline', 'wrapper_attributes');
     }
     // Add "form-group" class, don't replace "form-wrapper" as that is needed
     // by some JavaScript for certain functionality to work.
     if ($e->hasClass('form-wrapper')) {
         $e->addClass('form-group');
     }
     // Check for errors and set the "has_error" property flag.
     $errors = $e->getError();
     $e->setProperty('errors', $errors);
     if (isset($errors) || $e->getProperty('required') && $theme->getSetting('forms_required_has_error')) {
         $e->setProperty('has_error', TRUE);
     }
     // Automatically inject the nearest button found after this element if
     // #input_group_button exists.
     if ($e->getProperty('input_group_button')) {
         // Obtain the parent array to limit search.
         $array_parents = $e->getProperty('array_parents', []);
         // Remove the current element from the array.
         array_pop($array_parents);
         // If element is nested, return the referenced parent from the form.
         // Otherwise return the complete form.
         $parent = Element::create($array_parents ? NestedArray::getValue($complete_form, $array_parents) : $complete_form, $form_state);
         // Find the closest button.
         if ($button = self::findButton($parent)) {
             $e->setProperty('field_suffix', $button->setIcon()->getArray());
             $button->setProperty('access', FALSE);
         }
     }
     return $element;
 }
 /**
  * Get all system variables
  *
  * @return array()
  */
 public function getVariablesData()
 {
     $data = array();
     $variables = array('acquia_spi_send_node_user', 'acquia_spi_admin_priv', 'acquia_spi_module_diff_data', 'acquia_spi_send_watchdog', 'acquia_spi_use_cron', 'cache_backends', 'cache_default_class', 'cache_inc', 'cron_safe_threshold', 'googleanalytics_cache', 'error_level', 'preprocess_js', 'page_cache_maximum_age', 'block_cache', 'preprocess_css', 'page_compression', 'cache', 'cache_lifetime', 'cron_last', 'clean_url', 'redirect_global_clean', 'theme_zen_settings', 'site_offline', 'site_name', 'user_register', 'user_signatures', 'user_admin_role', 'user_email_verification', 'user_cancel_method', 'filter_fallback_format', 'dblog_row_limit', 'date_default_timezone', 'file_default_scheme', 'install_profile', 'maintenance_mode', 'update_last_check', 'site_default_country', 'acquia_spi_saved_variables', 'acquia_spi_set_variables_automatic', 'acquia_spi_ignored_set_variables', 'acquia_spi_set_variables_override');
     $allConfigData = self::getAllConfigs();
     $spi_def_vars = \Drupal::config('acquia_connector.settings')->get('spi.def_vars');
     $waived_spi_def_vars = \Drupal::config('acquia_connector.settings')->get('spi.def_waived_vars');
     // Merge hard coded $variables with vars from SPI definition.
     foreach ($spi_def_vars as $var_name => $var) {
         if (!in_array($var_name, $waived_spi_def_vars) && !in_array($var_name, $variables)) {
             $variables[] = $var_name;
         }
     }
     // @todo Add comment settings for node types.
     foreach ($variables as $name) {
         if (!empty($this->mapping[$name])) {
             // state
             if ($this->mapping[$name][0] == 'state' and !empty($this->mapping[$name][1])) {
                 $data[$name] = \Drupal::state()->get($this->mapping[$name][1]);
             } elseif ($this->mapping[$name][0] == 'settings' and !empty($this->mapping[$name][1])) {
                 $data[$name] = Settings::get($this->mapping[$name][1]);
             } else {
                 $key_exists = NULL;
                 $value = Utility\NestedArray::getValue($allConfigData, $this->mapping[$name], $key_exists);
                 if ($key_exists) {
                     $data[$name] = $value;
                 } else {
                     $data[$name] = 0;
                 }
             }
         } else {
             // @todo: Implement D8 way to update variables mapping.
             $data[$name] = 'Variable not implemented.';
         }
     }
     // Unset waived vars so they won't be sent to NSPI.
     foreach ($data as $var_name => $var) {
         if (in_array($var_name, $waived_spi_def_vars)) {
             unset($data[$var_name]);
         }
     }
     // Collapse to JSON string to simplify transport.
     return Json::encode($data);
 }
Exemplo n.º 16
0
 public function validateForm(array &$element, array &$form_state, \Payment $payment)
 {
     $values =& \Drupal\Component\Utility\NestedArray::getValue($form_state['values'], $element['#parents']);
     $method_data =& $payment->method_data;
     $method_data['holder'] = $values['holder'];
     if (empty($values['holder']) == TRUE) {
         form_error($element['holder'], t('Please enter the name of the account holder.'));
     }
     $method_data['iban'] = trim($values['ibanbic']['iban']);
     $method_data['bic'] = trim($values['ibanbic']['bic']);
     $method_data['country'] = substr($method_data['iban'], 0, 2);
     require_once dirname(__FILE__) . '/../php-iban.php';
     if (verify_iban($method_data['iban']) == FALSE) {
         form_error($element['ibanbic']['iban'], t('Please enter a valid IBAN.'));
     }
     if (preg_match('/^[a-z]{6}[2-9a-z][0-9a-np-z](|xxx|[0-9a-wyz][0-9a-z]{2})$/i', $method_data['bic']) != 1) {
         form_error($element['ibanbic']['bic'], t('Please enter a valid BIC.'));
     }
 }
 /**
  * Tests getting nested array values.
  *
  * @covers ::getValue
  */
 public function testGetValue()
 {
     // Verify getting a value of a nested element.
     $value = NestedArray::getValue($this->form, $this->parents);
     $this->assertSame('Nested element', $value['#value'], 'Nested element value found.');
     // Verify changing a value of a nested element by reference.
     $value =& NestedArray::getValue($this->form, $this->parents);
     $value['#value'] = 'New value';
     $value = NestedArray::getValue($this->form, $this->parents);
     $this->assertSame('New value', $value['#value'], 'Nested element value was changed by reference.');
     $this->assertSame('New value', $this->form['details']['element']['#value'], 'Nested element value was changed by reference.');
     // Verify that an existing key is reported back.
     $key_exists = NULL;
     NestedArray::getValue($this->form, $this->parents, $key_exists);
     $this->assertTrue($key_exists, 'Existing key found.');
     // Verify that a non-existing key is reported back and throws no errors.
     $key_exists = NULL;
     $parents = $this->parents;
     $parents[] = 'foo';
     NestedArray::getValue($this->form, $parents, $key_exists);
     $this->assertFalse($key_exists, 'Non-existing key not found.');
 }
 /**
  * Processes form submissions.
  *
  * From "Basic Form Generation and Processing in Drupal 8", chapter 4.
  */
 public function submitForm(array &$form, FormStateInterface $form_state)
 {
     // Extract the values submitted by the user.
     $values = $form_state->getValues();
     $name = $values['first_name'];
     // Values you stored in the form array are also available.
     $info = $values['information'];
     // Get another value, using a method where it could be nested.
     $parents = $form['company']['#array_parents'];
     $company = NestedArray::getValue($values, $parents);
     // Processing code would go here. As a proxy, display a message with the
     // values. Note that since the values are not sanitized, insert them
     // into t() with @variable. If inserting into the database, do not
     // sanitize.
     if ($company) {
         drupal_set_message($this->t('Thank you @name from @company', array('@name' => $name, '@company' => $company)));
     } else {
         drupal_set_message($this->t('Thank you @name', array('@name' => $name)));
     }
     // Make sure the form is rebuilt properly for Ajax.
     $form_state->setRebuild();
 }
Exemplo n.º 19
0
 /**
  * Validate helper to have support for other entity reference widgets.
  *
  * @param $element
  * @param FormStateInterface $form_state
  * @param $form
  */
 public static function targetTypeValidate($element, FormStateInterface $form_state, $form)
 {
     $values =& $form_state->getValues();
     $element_values = NestedArray::getValue($values, $element['#parents']);
     $bundle_options = array();
     if ($element_values) {
         $enabled = 0;
         foreach ($element_values as $machine_name => $bundle_info) {
             if (isset($bundle_info['enabled']) && $bundle_info['enabled']) {
                 $bundle_options[$machine_name] = $machine_name;
                 $enabled++;
             }
         }
         // All disabled = all enabled.
         if ($enabled === 0) {
             $bundle_options = NULL;
         }
     }
     // New value parents.
     $parents = array_merge(array_slice($element['#parents'], 0, -1), array('target_bundles'));
     NestedArray::setValue($values, $parents, $bundle_options);
 }
Exemplo n.º 20
0
 /**
  * Special submit handling.
  */
 public function submitOptionsForm(&$form, FormStateInterface $form_state) {
   $element = array('#parents' => array('query', 'options', 'query_tags'));
   $value = explode(',', NestedArray::getValue($form_state->getValues(), $element['#parents']));
   $value = array_filter(array_map('trim', $value));
   $form_state->setValueForElement($element, $value);
 }
 /**
  * Form submission handler for upload/remove button of formElement().
  *
  * This runs in addition to and after file_managed_file_submit().
  *
  * @see file_managed_file_submit()
  */
 public static function submit($form, FormStateInterface $form_state)
 {
     // During the form rebuild, formElement() will create field item widget
     // elements using re-indexed deltas, so clear out FormState::$input to
     // avoid a mismatch between old and new deltas. The rebuilt elements will
     // have #default_value set appropriately for the current state of the field,
     // so nothing is lost in doing this.
     $button = $form_state->getTriggeringElement();
     $parents = array_slice($button['#parents'], 0, -2);
     NestedArray::setValue($form_state->getUserInput(), $parents, NULL);
     // Go one level up in the form, to the widgets container.
     $element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -1));
     $field_name = $element['#field_name'];
     $parents = $element['#field_parents'];
     $submitted_values = NestedArray::getValue($form_state->getValues(), array_slice($button['#parents'], 0, -2));
     foreach ($submitted_values as $delta => $submitted_value) {
         if (empty($submitted_value['fids'])) {
             unset($submitted_values[$delta]);
         }
     }
     // If there are more files uploaded via the same widget, we have to separate
     // them, as we display each file in it's own widget.
     $new_values = array();
     foreach ($submitted_values as $delta => $submitted_value) {
         if (is_array($submitted_value['fids'])) {
             foreach ($submitted_value['fids'] as $fid) {
                 $new_value = $submitted_value;
                 $new_value['fids'] = array($fid);
                 $new_values[] = $new_value;
             }
         } else {
             $new_value = $submitted_value;
         }
     }
     // Re-index deltas after removing empty items.
     $submitted_values = array_values($new_values);
     // Update form_state values.
     NestedArray::setValue($form_state->getValues(), array_slice($button['#parents'], 0, -2), $submitted_values);
     // Update items.
     $field_state = static::getWidgetState($parents, $field_name, $form_state);
     $field_state['items'] = $submitted_values;
     static::setWidgetState($parents, $field_name, $form_state, $field_state);
 }
Exemplo n.º 22
0
 /**
  * {@inheritdoc}
  */
 public function getConfigurationItem($key)
 {
     $configuration = $this->getConfiguration();
     return NestedArray::getValue($configuration, (array) $key);
 }
Exemplo n.º 23
0
 /**
  * Submit handler for the menu overview form.
  *
  * This function takes great care in saving parent items first, then items
  * underneath them. Saving items in the incorrect order can break the tree.
  */
 protected function submitOverviewForm(array $complete_form, FormStateInterface $form_state)
 {
     // Form API supports constructing and validating self-contained sections
     // within forms, but does not allow to handle the form section's submission
     // equally separated yet. Therefore, we use a $form_state key to point to
     // the parents of the form section.
     $parents = $form_state->get('menu_overview_form_parents');
     $input = NestedArray::getValue($form_state->getUserInput(), $parents);
     $form =& NestedArray::getValue($complete_form, $parents);
     // When dealing with saving menu items, the order in which these items are
     // saved is critical. If a changed child item is saved before its parent,
     // the child item could be saved with an invalid path past its immediate
     // parent. To prevent this, save items in the form in the same order they
     // are sent, ensuring parents are saved first, then their children.
     // See https://www.drupal.org/node/181126#comment-632270.
     $order = is_array($input) ? array_flip(array_keys($input)) : array();
     // Update our original form with the new order.
     $form = array_intersect_key(array_merge($order, $form), $form);
     $fields = array('weight', 'parent', 'enabled');
     $form_links = $form['links'];
     foreach (Element::children($form_links) as $id) {
         if (isset($form_links[$id]['#item'])) {
             $element = $form_links[$id];
             $updated_values = array();
             // Update any fields that have changed in this menu item.
             foreach ($fields as $field) {
                 if ($element[$field]['#value'] != $element[$field]['#default_value']) {
                     $updated_values[$field] = $element[$field]['#value'];
                 }
             }
             if ($updated_values) {
                 // Use the ID from the actual plugin instance since the hidden value
                 // in the form could be tampered with.
                 $this->menuLinkManager->updateDefinition($element['#item']->link->getPLuginId(), $updated_values);
             }
         }
     }
 }
Exemplo n.º 24
0
 /**
  * {@inheritdoc}
  */
 public function getSetting($name)
 {
     if (is_array($name)) {
         if (NestedArray::keyExists($this->settings, $name)) {
             return NestedArray::getValue($this->settings, $name);
         } elseif ($plugin = $this->getPlugin()) {
             $defaults = $plugin->defaultSettings();
             return NestedArray::getValue($defaults, $name);
         }
     } else {
         if (isset($this->settings[$name])) {
             return $this->settings[$name];
         } elseif ($plugin = $this->getPlugin()) {
             $defaults = $plugin->defaultSettings();
             if (isset($defaults[$name])) {
                 return $defaults[$name];
             }
         }
     }
 }
Exemplo n.º 25
0
 /**
  * Gets data from this configuration object.
  *
  * @param string $key
  *   A string that maps to a key within the configuration data.
  *   For instance in the following configuration array:
  *   @code
  *   array(
  *     'foo' => array(
  *       'bar' => 'baz',
  *     ),
  *   );
  *   @endcode
  *   A key of 'foo.bar' would return the string 'baz'. However, a key of 'foo'
  *   would return array('bar' => 'baz').
  *   If no key is specified, then the entire data array is returned.
  *
  * @return mixed
  *   The data that was requested.
  */
 public function get($key = '')
 {
     if (empty($key)) {
         return $this->data;
     } else {
         $parts = explode('.', $key);
         if (count($parts) == 1) {
             return isset($this->data[$key]) ? $this->data[$key] : NULL;
         } else {
             $value = NestedArray::getValue($this->data, $parts, $key_exists);
             return $key_exists ? $value : NULL;
         }
     }
 }
Exemplo n.º 26
0
 /**
  * Processes elements that have input groups.
  *
  * @param \Drupal\bootstrap\Utility\Element $element
  *   The element object.
  * @param \Drupal\Core\Form\FormStateInterface $form_state
  *   The current state of the form.
  * @param array $complete_form
  *   The complete form structure.
  */
 protected static function processInputGroups(Element $element, FormStateInterface $form_state, array &$complete_form)
 {
     // Automatically inject the nearest button found after this element if
     // #input_group_button exists.
     if ($element->getProperty('input_group_button')) {
         // Obtain the parent array to limit search.
         $array_parents = $element->getProperty('array_parents', []);
         // Remove the current element from the array.
         array_pop($array_parents);
         // Retrieve the parent element.
         $parent = Element::create(NestedArray::getValue($complete_form, $array_parents), $form_state);
         // Find the closest button.
         if ($button = self::findButton($parent)) {
             $element->appendProperty('field_suffix', $button->setIcon());
             $button->setProperty('access', FALSE);
         }
     }
     $input_group_attributes = ['class' => ['input-group-' . ($element->getProperty('input_group_button') ? 'btn' : 'addon')]];
     if ($prefix = $element->getProperty('field_prefix')) {
         $element->setProperty('field_prefix', ['#type' => 'html_tag', '#tag' => 'span', '#attributes' => $input_group_attributes, '#value' => Element::create($prefix)->render(), '#weight' => -1]);
     }
     if ($suffix = $element->getProperty('field_suffix')) {
         $element->setProperty('field_suffix', ['#type' => 'html_tag', '#tag' => 'span', '#attributes' => $input_group_attributes, '#value' => Element::create($suffix)->render(), '#weight' => 1]);
     }
 }
Exemplo n.º 27
0
 /**
  * Adds the #name and #value properties of an input element before rendering.
  */
 protected function handleInputElement($form_id, &$element, FormStateInterface &$form_state)
 {
     if (!isset($element['#name'])) {
         $name = array_shift($element['#parents']);
         $element['#name'] = $name;
         if ($element['#type'] == 'file') {
             // To make it easier to handle files in file.inc, we place all
             // file fields in the 'files' array. Also, we do not support
             // nested file names.
             // @todo Remove this files prefix now?
             $element['#name'] = 'files[' . $element['#name'] . ']';
         } elseif (count($element['#parents'])) {
             $element['#name'] .= '[' . implode('][', $element['#parents']) . ']';
         }
         array_unshift($element['#parents'], $name);
     }
     // Setting #disabled to TRUE results in user input being ignored regardless
     // of how the element is themed or whether JavaScript is used to change the
     // control's attributes. However, it's good UI to let the user know that
     // input is not wanted for the control. HTML supports two attributes for:
     // this: http://www.w3.org/TR/html401/interact/forms.html#h-17.12. If a form
     // wants to start a control off with one of these attributes for UI
     // purposes, only, but still allow input to be processed if it's submitted,
     // it can set the desired attribute in #attributes directly rather than
     // using #disabled. However, developers should think carefully about the
     // accessibility implications of doing so: if the form expects input to be
     // enterable under some condition triggered by JavaScript, how would someone
     // who has JavaScript disabled trigger that condition? Instead, developers
     // should consider whether a multi-step form would be more appropriate
     // (#disabled can be changed from step to step). If one still decides to use
     // JavaScript to affect when a control is enabled, then it is best for
     // accessibility for the control to be enabled in the HTML, and disabled by
     // JavaScript on document ready.
     if (!empty($element['#disabled'])) {
         if (!empty($element['#allow_focus'])) {
             $element['#attributes']['readonly'] = 'readonly';
         } else {
             $element['#attributes']['disabled'] = 'disabled';
         }
     }
     // With JavaScript or other easy hacking, input can be submitted even for
     // elements with #access=FALSE or #disabled=TRUE. For security, these must
     // not be processed. Forms that set #disabled=TRUE on an element do not
     // expect input for the element, and even forms submitted with
     // self::submitForm() must not be able to get around this. Forms that set
     // #access=FALSE on an element usually allow access for some users, so forms
     // submitted with self::submitForm() may bypass access restriction and be
     // treated as high-privilege users instead.
     $process_input = empty($element['#disabled']) && ($form_state->isProgrammed() && $form_state->isBypassingProgrammedAccessChecks() || $form_state->isProcessingInput() && (!isset($element['#access']) || $element['#access']));
     // Set the element's #value property.
     if (!isset($element['#value']) && !array_key_exists('#value', $element)) {
         // @todo Once all elements are converted to plugins in
         //   https://www.drupal.org/node/2311393, rely on
         //   $element['#value_callback'] directly.
         $value_callable = !empty($element['#value_callback']) ? $element['#value_callback'] : 'form_type_' . $element['#type'] . '_value';
         if (!is_callable($value_callable)) {
             $value_callable = '\\Drupal\\Core\\Render\\Element\\FormElement::valueCallback';
         }
         if ($process_input) {
             // Get the input for the current element. NULL values in the input need
             // to be explicitly distinguished from missing input. (see below)
             $input_exists = NULL;
             $input = NestedArray::getValue($form_state->getUserInput(), $element['#parents'], $input_exists);
             // For browser-submitted forms, the submitted values do not contain
             // values for certain elements (empty multiple select, unchecked
             // checkbox). During initial form processing, we add explicit NULL
             // values for such elements in FormState::$input. When rebuilding the
             // form, we can distinguish elements having NULL input from elements
             // that were not part of the initially submitted form and can therefore
             // use default values for the latter, if required. Programmatically
             // submitted forms can submit explicit NULL values when calling
             // self::submitForm() so we do not modify FormState::$input for them.
             if (!$input_exists && !$form_state->isRebuilding() && !$form_state->isProgrammed()) {
                 // Add the necessary parent keys to FormState::$input and sets the
                 // element's input value to NULL.
                 NestedArray::setValue($form_state->getUserInput(), $element['#parents'], NULL);
                 $input_exists = TRUE;
             }
             // If we have input for the current element, assign it to the #value
             // property, optionally filtered through $value_callback.
             if ($input_exists) {
                 // Skip all value callbacks except safe ones like text if the CSRF
                 // token was invalid.
                 if (!$form_state->hasInvalidToken() || $this->valueCallableIsSafe($value_callable)) {
                     $element['#value'] = call_user_func_array($value_callable, array(&$element, $input, &$form_state));
                 } else {
                     $input = NULL;
                 }
                 if (!isset($element['#value']) && isset($input)) {
                     $element['#value'] = $input;
                 }
             }
             // Mark all posted values for validation.
             if (isset($element['#value']) || !empty($element['#required'])) {
                 $element['#needs_validation'] = TRUE;
             }
         }
         // Load defaults.
         if (!isset($element['#value'])) {
             // Call #type_value without a second argument to request default_value
             // handling.
             $element['#value'] = call_user_func_array($value_callable, array(&$element, FALSE, &$form_state));
             // Final catch. If we haven't set a value yet, use the explicit default
             // value. Avoid image buttons (which come with garbage value), so we
             // only get value for the button actually clicked.
             if (!isset($element['#value']) && empty($element['#has_garbage_value'])) {
                 $element['#value'] = isset($element['#default_value']) ? $element['#default_value'] : '';
             }
         }
     }
     // Determine which element (if any) triggered the submission of the form and
     // keep track of all the clickable buttons in the form for
     // \Drupal\Core\Form\FormState::cleanValues(). Enforce the same input
     // processing restrictions as above.
     if ($process_input) {
         // Detect if the element triggered the submission via Ajax.
         if ($this->elementTriggeredScriptedSubmission($element, $form_state)) {
             $form_state->setTriggeringElement($element);
         }
         // If the form was submitted by the browser rather than via Ajax, then it
         // can only have been triggered by a button, and we need to determine
         // which button within the constraints of how browsers provide this
         // information.
         if (!empty($element['#is_button'])) {
             // All buttons in the form need to be tracked for
             // \Drupal\Core\Form\FormState::cleanValues() and for the
             // self::doBuildForm() code that handles a form submission containing no
             // button information in \Drupal::request()->request.
             $buttons = $form_state->getButtons();
             $buttons[] = $element;
             $form_state->setButtons($buttons);
             if ($this->buttonWasClicked($element, $form_state)) {
                 $form_state->setTriggeringElement($element);
             }
         }
     }
     // Set the element's value in $form_state->getValues(), but only, if its key
     // does not exist yet (a #value_callback may have already populated it).
     if (!NestedArray::keyExists($form_state->getValues(), $element['#parents'])) {
         $form_state->setValueForElement($element, $element['#value']);
     }
 }
 /**
  * Extracts the layout settings form and form state from the full form.
  *
  * @param array $form
  *   Full form array.
  * @param \Drupal\Core\Form\FormStateInterface $form_state
  *   Full form state.
  *
  * @return array
  *   An array with two values: the new form array and form state object.
  */
 protected function getLayoutSettingsForm(array &$form, FormStateInterface $form_state)
 {
     $layout_settings_form = NestedArray::getValue($form, array_merge($form['#variant_array_parents'], ['layout_settings_wrapper', 'layout_settings']));
     $layout_settings_form_state = (new FormState())->setValues($form_state->getValue('layout_settings'));
     return [$layout_settings_form, $layout_settings_form_state];
 }
Exemplo n.º 29
0
 /**
  * Render API callback: gets the layout settings elements.
  */
 public static function formatterSettingsAjaxCallback(array $form, FormStateInterface $form_state)
 {
     $formatter_array_parents = $form['#formatter_array_parents'];
     return NestedArray::getValue($form, array_merge($formatter_array_parents, ['formatter_settings_wrapper']));
 }
 /**
  * Gets the current value of a #select element, from within a form constructor function.
  *
  * This function is intended for use in highly dynamic forms (in particular the
  * add view wizard) which are rebuilt in different ways depending on which
  * triggering element (AJAX or otherwise) was most recently fired. For example,
  * sometimes it is necessary to decide how to build one dynamic form element
  * based on the value of a different dynamic form element that may not have
  * even been present on the form the last time it was submitted. This function
  * takes care of resolving those conflicts and gives you the proper current
  * value of the requested #select element.
  *
  * By necessity, this function sometimes uses non-validated user input from
  * FormState::$input in making its determination. Although it performs some
  * minor validation of its own, it is not complete. The intention is that the
  * return value of this function should only be used to help decide how to
  * build the current form the next time it is reloaded, not to be saved as if
  * it had gone through the normal, final form validation process. Do NOT use
  * the results of this function for any other purpose besides deciding how to
  * build the next version of the form.
  *
  * @param \Drupal\Core\Form\FormStateInterface $form_state
  *   The current state of the form.
  * @param $parents
  *   An array of parent keys that point to the part of the submitted form
  *   values that are expected to contain the element's value (in the case where
  *   this form element was actually submitted). In a simple case (assuming
  *   #tree is TRUE throughout the form), if the select element is located in
  *   $form['wrapper']['select'], so that the submitted form values would
  *   normally be found in $form_state->getValue(array('wrapper', 'select')),
  *   you would pass array('wrapper', 'select') for this parameter.
  * @param $default_value
  *   The default value to return if the #select element does not currently have
  *   a proper value set based on the submitted input.
  * @param $element
  *   An array representing the current version of the #select element within
  *   the form.
  *
  * @return
  *   The current value of the #select element. A common use for this is to feed
  *   it back into $element['#default_value'] so that the form will be rendered
  *   with the correct value selected.
  */
 public static function getSelected(FormStateInterface $form_state, $parents, $default_value, $element)
 {
     // For now, don't trust this to work on anything but a #select element.
     if (!isset($element['#type']) || $element['#type'] != 'select' || !isset($element['#options'])) {
         return $default_value;
     }
     // If there is a user-submitted value for this element that matches one of
     // the currently available options attached to it, use that. We need to check
     // FormState::$input rather than $form_state->getValues() here because the
     // triggering element often has the #limit_validation_errors property set to
     // prevent unwanted errors elsewhere on the form. This means that the
     // $form_state->getValues() array won't be complete. We could make it complete
     // by adding each required part of the form to the #limit_validation_errors
     // property individually as the form is being built, but this is difficult to
     // do for a highly dynamic and extensible form. This method is much simpler.
     $user_input =& $form_state->getUserInput();
     if (!empty($user_input)) {
         $key_exists = NULL;
         $submitted = NestedArray::getValue($user_input, $parents, $key_exists);
         // Check that the user-submitted value is one of the allowed options before
         // returning it. This is not a substitute for actual form validation;
         // rather it is necessary because, for example, the same select element
         // might have #options A, B, and C under one set of conditions but #options
         // D, E, F under a different set of conditions. So the form submission
         // might have occurred with option A selected, but when the form is rebuilt
         // option A is no longer one of the choices. In that case, we don't want to
         // use the value that was submitted anymore but rather fall back to the
         // default value.
         if ($key_exists && in_array($submitted, array_keys($element['#options']))) {
             return $submitted;
         }
     }
     // Fall back on returning the default value if nothing was returned above.
     return $default_value;
 }