Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
25.00% |
1 / 4 |
CRAP | |
56.45% |
35 / 62 |
| MachineName | |
0.00% |
0 / 1 |
|
25.00% |
1 / 4 |
40.87 | |
56.45% |
35 / 62 |
| getInfo | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 10 |
|||
| valueCallback | |
100.00% |
1 / 1 |
4 | |
100.00% |
3 / 3 |
|||
| processMachineName | |
0.00% |
0 / 1 |
5.03 | |
88.89% |
32 / 36 |
|||
| validateMachineName | |
0.00% |
0 / 1 |
56 | |
0.00% |
0 / 13 |
|||
| <?php | |
| /** | |
| * @file | |
| * Contains \Drupal\Core\Render\Element\MachineName. | |
| */ | |
| namespace Drupal\Core\Render\Element; | |
| use Drupal\Component\Utility\NestedArray; | |
| use Drupal\Core\Form\FormStateInterface; | |
| use Drupal\Core\Language\LanguageInterface; | |
| /** | |
| * Provides a machine name render element. | |
| * | |
| * Provides a form element to enter a machine name, which is validated to ensure | |
| * that the name is unique and does not contain disallowed characters. | |
| * | |
| * The element may be automatically populated via JavaScript when used in | |
| * conjunction with a separate "source" form element (typically specifying the | |
| * human-readable name). As the user types text into the source element, the | |
| * JavaScript converts all values to lower case, replaces any remaining | |
| * disallowed characters with a replacement, and populates the associated | |
| * machine name form element. | |
| * | |
| * Properties: | |
| * - #machine_name: An associative array containing: | |
| * - exists: A callable to invoke for checking whether a submitted machine | |
| * name value already exists. The submitted value is passed as an argument. | |
| * In most cases, an existing API or menu argument loader function can be | |
| * re-used. The callback is only invoked if the submitted value differs from | |
| * the element's #default_value. | |
| * - source: (optional) The #array_parents of the form element containing the | |
| * human-readable name (i.e., as contained in the $form structure) to use as | |
| * source for the machine name. Defaults to array('label'). | |
| * - label: (optional) Text to display as label for the machine name value | |
| * after the human-readable name form element. Defaults to t('Machine name'). | |
| * - replace_pattern: (optional) A regular expression (without delimiters) | |
| * matching disallowed characters in the machine name. Defaults to | |
| * '[^a-z0-9_]+'. | |
| * - replace: (optional) A character to replace disallowed characters in the | |
| * machine name via JavaScript. Defaults to '_' (underscore). When using a | |
| * different character, 'replace_pattern' needs to be set accordingly. | |
| * - error: (optional) A custom form error message string to show, if the | |
| * machine name contains disallowed characters. | |
| * - standalone: (optional) Whether the live preview should stay in its own | |
| * form element rather than in the suffix of the source element. Defaults | |
| * to FALSE. | |
| * - #maxlength: (optional) Maximum allowed length of the machine name. Defaults | |
| * to 64. | |
| * - #disabled: (optional) Should be set to TRUE if an existing machine name | |
| * must not be changed after initial creation. | |
| * | |
| * Usage example: | |
| * @code | |
| * $form['id'] = array( | |
| * '#type' => 'machine_name', | |
| * '#default_value' => $this->entity->id(), | |
| * '#disabled' => !$this->entity->isNew(), | |
| * '#maxlength' => 64, | |
| * '#description' => $this->t('A unique name for this item. It must only contain lowercase letters, numbers, and underscores.'), | |
| * '#machine_name' => array( | |
| * 'exists' => array($this, 'exists'), | |
| * ), | |
| * ); | |
| * @endcode | |
| * | |
| * @see \Drupal\Core\Render\Element\Textfield | |
| * | |
| * @FormElement("machine_name") | |
| */ | |
| class MachineName extends Textfield { | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function getInfo() { | |
| $class = get_class($this); | |
| return array( | |
| '#input' => TRUE, | |
| '#default_value' => NULL, | |
| '#required' => TRUE, | |
| '#maxlength' => 64, | |
| '#size' => 60, | |
| '#autocomplete_route_name' => FALSE, | |
| '#process' => array( | |
| array($class, 'processMachineName'), | |
| array($class, 'processAutocomplete'), | |
| array($class, 'processAjaxForm'), | |
| ), | |
| '#element_validate' => array( | |
| array($class, 'validateMachineName'), | |
| ), | |
| '#pre_render' => array( | |
| array($class, 'preRenderTextfield'), | |
| ), | |
| '#theme' => 'input__textfield', | |
| '#theme_wrappers' => array('form_element'), | |
| ); | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public static function valueCallback(&$element, $input, FormStateInterface $form_state) { | |
| if ($input !== FALSE && $input !== NULL) { | |
| // This should be a string, but allow other scalars since they might be | |
| // valid input in programmatic form submissions. | |
| return is_scalar($input) ? (string) $input : ''; | |
| } | |
| return NULL; | |
| } | |
| /** | |
| * Processes a machine-readable name form element. | |
| * | |
| * @param array $element | |
| * The form element to process. See main class documentation for properties. | |
| * @param \Drupal\Core\Form\FormStateInterface $form_state | |
| * The current state of the form. | |
| * @param array $complete_form | |
| * The complete form structure. | |
| * | |
| * @return array | |
| * The processed element. | |
| */ | |
| public static function processMachineName(&$element, FormStateInterface $form_state, &$complete_form) { | |
| // We need to pass the langcode to the client. | |
| $language = \Drupal::languageManager()->getCurrentLanguage(); | |
| // Apply default form element properties. | |
| $element += array( | |
| '#title' => t('Machine-readable name'), | |
| '#description' => t('A unique machine-readable name. Can only contain lowercase letters, numbers, and underscores.'), | |
| '#machine_name' => array(), | |
| '#field_prefix' => '', | |
| '#field_suffix' => '', | |
| '#suffix' => '', | |
| ); | |
| // A form element that only wants to set one #machine_name property (usually | |
| // 'source' only) would leave all other properties undefined, if the defaults | |
| // were defined by an element plugin. Therefore, we apply the defaults here. | |
| $element['#machine_name'] += array( | |
| 'source' => array('label'), | |
| 'target' => '#' . $element['#id'], | |
| 'label' => t('Machine name'), | |
| 'replace_pattern' => '[^a-z0-9_]+', | |
| 'replace' => '_', | |
| 'standalone' => FALSE, | |
| 'field_prefix' => $element['#field_prefix'], | |
| 'field_suffix' => $element['#field_suffix'], | |
| ); | |
| // By default, machine names are restricted to Latin alphanumeric characters. | |
| // So, default to LTR directionality. | |
| if (!isset($element['#attributes'])) { | |
| $element['#attributes'] = array(); | |
| } | |
| $element['#attributes'] += array('dir' => LanguageInterface::DIRECTION_LTR); | |
| // The source element defaults to array('name'), but may have been overridden. | |
| if (empty($element['#machine_name']['source'])) { | |
| return $element; | |
| } | |
| // Retrieve the form element containing the human-readable name from the | |
| // complete form in $form_state. By reference, because we may need to append | |
| // a #field_suffix that will hold the live preview. | |
| $key_exists = NULL; | |
| $source = NestedArray::getValue($form_state->getCompleteForm(), $element['#machine_name']['source'], $key_exists); | |
| if (!$key_exists) { | |
| return $element; | |
| } | |
| $suffix_id = $source['#id'] . '-machine-name-suffix'; | |
| $element['#machine_name']['suffix'] = '#' . $suffix_id; | |
| if ($element['#machine_name']['standalone']) { | |
| $element['#suffix'] = $element['#suffix'] . ' <small id="' . $suffix_id . '"> </small>'; | |
| } | |
| else { | |
| // Append a field suffix to the source form element, which will contain | |
| // the live preview of the machine name. | |
| $source += array('#field_suffix' => ''); | |
| $source['#field_suffix'] = $source['#field_suffix'] . ' <small id="' . $suffix_id . '"> </small>'; | |
| $parents = array_merge($element['#machine_name']['source'], array('#field_suffix')); | |
| NestedArray::setValue($form_state->getCompleteForm(), $parents, $source['#field_suffix']); | |
| } | |
| $element['#attached']['library'][] = 'core/drupal.machine-name'; | |
| $options = [ | |
| 'replace_pattern', | |
| 'replace', | |
| 'maxlength', | |
| 'target', | |
| 'label', | |
| 'field_prefix', | |
| 'field_suffix', | |
| 'suffix', | |
| ]; | |
| $element['#attached']['drupalSettings']['machineName']['#' . $source['#id']] = array_intersect_key($element['#machine_name'], array_flip($options)); | |
| $element['#attached']['drupalSettings']['langcode'] = $language->getId(); | |
| return $element; | |
| } | |
| /** | |
| * Form element validation handler for machine_name elements. | |
| * | |
| * Note that #maxlength is validated by _form_validate() already. | |
| * | |
| * This checks that the submitted value: | |
| * - Does not contain the replacement character only. | |
| * - Does not contain disallowed characters. | |
| * - Is unique; i.e., does not already exist. | |
| * - Does not exceed the maximum length (via #maxlength). | |
| * - Cannot be changed after creation (via #disabled). | |
| */ | |
| public static function validateMachineName(&$element, FormStateInterface $form_state, &$complete_form) { | |
| // Verify that the machine name not only consists of replacement tokens. | |
| if (preg_match('@^' . $element['#machine_name']['replace'] . '+$@', $element['#value'])) { | |
| $form_state->setError($element, t('The machine-readable name must contain unique characters.')); | |
| } | |
| // Verify that the machine name contains no disallowed characters. | |
| if (preg_match('@' . $element['#machine_name']['replace_pattern'] . '@', $element['#value'])) { | |
| if (!isset($element['#machine_name']['error'])) { | |
| // Since a hyphen is the most common alternative replacement character, | |
| // a corresponding validation error message is supported here. | |
| if ($element['#machine_name']['replace'] == '-') { | |
| $form_state->setError($element, t('The machine-readable name must contain only lowercase letters, numbers, and hyphens.')); | |
| } | |
| // Otherwise, we assume the default (underscore). | |
| else { | |
| $form_state->setError($element, t('The machine-readable name must contain only lowercase letters, numbers, and underscores.')); | |
| } | |
| } | |
| else { | |
| $form_state->setError($element, $element['#machine_name']['error']); | |
| } | |
| } | |
| // Verify that the machine name is unique. | |
| if ($element['#default_value'] !== $element['#value']) { | |
| $function = $element['#machine_name']['exists']; | |
| if (call_user_func($function, $element['#value'], $element, $form_state)) { | |
| $form_state->setError($element, t('The machine-readable name is already in use. It must be unique.')); | |
| } | |
| } | |
| } | |
| } |