1 layout.admin.inc layout_settings_form_validate(&$form, &$form_state)

Validates layout_settings_form(), ensuring a valid path.

File

core/modules/layout/layout.admin.inc, line 970
Admin page callbacks for the Layout module.

Code

function layout_settings_form_validate(&$form, &$form_state) {
  /** @var Layout $layout */
  $layout = $form_state['layout'];

  // Remove trailing and preceding slashes.
  $path = $form_state['values']['path'] = trim($form_state['values']['path'], '/');

  if (strpos($path, '%') === 0) {
    form_error($form['path'], t('The first part of a path may not be a placeholder.'));
  }

  // Ensure the path is not already an alias to something else.
  if (strpos($path, '%') === FALSE) {
    $alias = db_query('SELECT * FROM {url_alias} WHERE alias = :path', array(':path' => $path))->fetchObject();
    if ($alias) {
      $error = t('That path is currently assigned to be an alias for "@alias".', array('@alias' => $alias->source));
      if (user_access('administer url aliases')) {
        $error .= ' ' . t('<a href="!url">Delete the alias first</a>, then save this layout.', array('!url' => url('admin/config/urls/path/delete/' . $alias->pid, array('query' => array('destination' => $_GET['q'])))));
      }
      form_error($form['path'], $error);
    }
  }

  // Ensure path is properly formed.
  _layout_set_message_on_path_error($form, 'path', $path);

  // Ensure that all conditions have context requirements met.
  $context_plugins = array(
    'user', // The user plugin is always available for the current user.
  );
  $contexts = layout_context_required_by_path($path);
  foreach ($contexts as $context) {
    $context_plugins[] = $context->plugin;
  }

  if ($form_state['clicked_button']['#value'] == t('Remove')) {
    $key = $form_state['clicked_button']['#attributes']['data-layout-additional-path-remove'];
    unset($form_state['additional_paths'][$key]);
  }

  if (isset($form_state['values']['additional_paths'])) {
    foreach ($form_state['values']['additional_paths'] as $key => $additional_path) {
      $additional_path = trim($additional_path);
      if (!empty($additional_path)) {
        $alias = NULL;
        // Validation for if the primary path has placeholders.
        if (strpos($path, '%') !== FALSE) {
          // We check string length so we don't throw an error on each
          // keystroke since this function runs on keyup when typing paths.

          // Additional paths must have the same contexts as the main paths.
          $path_parts = explode('%', $path);
          $additional_path_parts = explode('%', $additional_path);
          $count_path_parts = count($path_parts);
          $count_additional_path_parts = count($additional_path_parts);

          if (!isset($additional_path_parts[1])) {
            if (strpos($path, $additional_path) === FALSE) {
              form_set_error('additional_paths_wrapper', t('Additional path %path must match primary path %primary_path since the primary path has placeholders (%).', 
              array(
                '%path' => $additional_path,
                '%primary_path' => $path,
              )
              ));
            }
          }
          else {
            // Path parts must match up to the last wildcard, otherwise we
            // cannot be sure about context positions.
            if (abs($count_additional_path_parts - $count_path_parts) > 1) {
              form_set_error('additional_paths', t('Additional path %path should have the same number of placeholders as primary path %primary_path.', 
              array(
                '%path' => $additional_path,
                '%primary_path' => $path,
              )
              ));
            }
            elseif ($count_additional_path_parts !== $count_path_parts) {
              foreach ($path_parts as $i => $path_part) {
                if (isset($additional_path_parts[$i]) && $additional_path_parts[$i] !== $path_parts[$i]) {
                  form_set_error('additional_paths', t('Additional path %path should have the same number of placeholders as primary path %primary_path.', 
                  array(
                    '%path' => $additional_path,
                    '%primary_path' => $path,
                  )
                  ));
                  break;
                }
              }
            }
            if ($path_parts[0] != $additional_path_parts[0]) {
              form_set_error('additional_paths_wrapper', t('Additional path %path must match primary path %primary_path since the primary path has placeholders (%).', 
              array(
                '%path' => $additional_path,
                '%primary_path' => $path,
              )
              ));
            }
          }
        }
        else {
          if (strpos($additional_path, '%')) {
            form_set_error('additional_paths_wrapper', t('Additional path %path must match primary path %primary_path since the primary path has no placeholders (%).', 
            array(
              '%path' => $additional_path,
              '%primary_path' => $path,
            )
            ));
          }

          // An additional path like node/5 shouldnt be allowed if there is not
          // a context-generating path as primary. But anypath/5 would be fine
          // as a layout-provided path.
          $all_info = _layout_get_all_info('layout_context');
          $split_additional_path = preg_split('/\/[0-9_]+/', $additional_path);
          $cleaned_additional_path = $split_additional_path[0];
          foreach ($all_info as $context_info) {
            foreach ($context_info['menu paths'] as $context_path) {
              $cleaned_path = preg_replace('/%[a-z0-9_]+/', '%', $context_path);
              if ($cleaned_path == $cleaned_additional_path . '/%') {
                form_set_error('additional_paths_wrapper', t('Additional path %path cannot be used as an additional path. It requires a context in the primary path.', 
                array(
                  '%path' => $additional_path,
                )
                ));
                break 2;
              }
            }
          }
        }
        if (strpos($additional_path, '%') === FALSE) {
          $alias = db_query('SELECT * FROM {url_alias} WHERE alias = :path', array(':path' => $additional_path))->fetchObject();
          if (!empty($alias)) {
            // E.g. "about" is an alias of "node/2".
            form_set_error('additional_paths_wrapper', t('Additional path %path is currently assigned to be an alias for "@alias" and cannot be used.', 
            array(
              '%path' => $additional_path,
              '@alias' => $alias->source,
            )
            ));
          }
        }

        // If no errors, save the additional path.
        $form_state['additional_paths'][$key] = $additional_path;

        // @todo: may not need this. Only if subcontexts like node/%/etc/% allowed.
        $contexts_from_additional_paths = layout_context_required_by_path($additional_path);
        foreach ($contexts_from_additional_paths as $contexts_from_additional_path) {
          $context_plugins[] = $contexts_from_additional_path->plugin;
        }
      }
    }
  }

  foreach ($layout->conditions as $key => $condition) {
    $required_contexts = $condition->getRequiredContexts();
    if (array_diff($required_contexts, $context_plugins)) {
      form_error($form['conditions']['active'][$key], t('The condition \'!condition\' does not have the required contexts at this path. Remove the condition to save the layout.', array('!condition' => $condition->summary())));
    }
  }
}