Commit ce8dcd40 authored by alexpott's avatar alexpott

Issue #2321745 by larowlan, tim.plunkett: Add #type => 'path' that accepts...

Issue #2321745 by larowlan, tim.plunkett: Add #type => 'path' that accepts path but optionally stores URL object or route name and parameters.
parent b3d9f457
<?php
/**
* @file
* Contains \Drupal\Core\Render\Element\PathElement.
*/
namespace Drupal\Core\Render\Element;
use Drupal\Core\Form\FormStateInterface;
/**
* Provides a matched path render element.
*
* Provides a form element to enter a path which can be optionally validated and
* stored as either a \Drupal\Core\Url value object or a array containing a
* route name and route parameters pair.
*
* @FormElement("path")
*/
class PathElement extends Textfield {
/**
* Do not convert the submitted value from the user-supplied path.
*/
const CONVERT_NONE = 0;
/**
* Convert the submitted value into a route name and parameter pair.
*/
const CONVERT_ROUTE = 1;
/**
* Convert the submitted value into a \Drupal\Core\Url value object.
*/
const CONVERT_URL = 2;
/**
* {@inheritdoc}
*/
public function getInfo() {
$info = parent::getInfo();
$class = get_class($this);
$info['#validate_path'] = TRUE;
$info['#convert_path'] = self::CONVERT_ROUTE;
$info['#element_validate'] = array(
array($class, 'validateMatchedPath'),
);
return $info;
}
/**
* {@inheritdoc}
*/
public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
return NULL;
}
/**
* Form element validation handler for matched_path elements.
*
* Note that #maxlength is validated by _form_validate() already.
*
* This checks that the submitted value matches an active route.
*/
public static function validateMatchedPath(&$element, FormStateInterface $form_state, &$complete_form) {
if (!empty($element['#value']) && ($element['#validate_path'] || $element['#convert_path'] != self::CONVERT_NONE)) {
/** @var \Drupal\Core\Url $url */
if ($url = \Drupal::service('path.validator')->getUrlIfValid($element['#value'])) {
if ($url->isExternal()) {
$form_state->setError($element, t('You cannot use an external URL, please enter a relative path.'));
return;
}
if ($element['#convert_path'] == self::CONVERT_NONE) {
// Url is valid, no conversion required.
return;
}
// We do the value conversion here whilst the Url object is in scope
// after validation has occurred.
if ($element['#convert_path'] == self::CONVERT_ROUTE) {
$form_state->setValueForElement($element, array(
'route_name' => $url->getRouteName(),
'route_parameters' => $url->getRouteParameters(),
));
return;
}
elseif ($element['#convert_path'] == self::CONVERT_URL) {
$form_state->setValueForElement($element, $url);
return;
}
}
$form_state->setError($element, t('This path does not exist or you do not have permission to link to %path.', array(
'%path' => $element['#value'],
)));
}
}
}
<?php
/**
* @file
* Contains \Drupal\system\Tests\Element\PathElementFormTest.
*/
namespace Drupal\system\Tests\Element;
use Drupal\Core\Form\FormInterface;
use Drupal\Core\Form\FormState;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element\PathElement;
use Drupal\Core\Url;
use Drupal\simpletest\KernelTestBase;
use Drupal\user\Entity\Role;
use Drupal\user\Entity\User;
/**
* Tests PathElement validation and conversion functionality.
*
* @group Form
*/
class PathElementFormTest extends KernelTestBase implements FormInterface {
/**
* User for testing.
*
* @var \Drupal\user\UserInterface
*/
protected $testUser;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('system', 'user');
/**
* Sets up the test.
*/
protected function setUp() {
parent::setUp();
$this->installSchema('system', array('router', 'sequences'));
$this->installEntitySchema('user');
\Drupal::service('router.builder')->rebuild();
/** @var \Drupal\user\RoleInterface $role */
$role = Role::create(array(
'id' => 'admin',
'label' => 'admin',
));
$role->grantPermission('link to any page');
$role->save();
$this->testUser = User::create(array(
'name' => 'foobar',
'mail' => 'foobar@example.com',
));
$this->testUser->addRole($role->id());
$this->testUser->save();
\Drupal::service('current_user')->setAccount($this->testUser);
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'test_path_element';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
// A required validated path.
$form['required_validate'] = array(
'#type' => 'path',
'#required' => TRUE,
'#title' => 'required_validate',
'#convert_path' => PathElement::CONVERT_NONE,
);
// A non validated required path.
$form['required_non_validate'] = array(
'#type' => 'path',
'#required' => TRUE,
'#title' => 'required_non_validate',
'#convert_path' => PathElement::CONVERT_NONE,
'#validate_path' => FALSE,
);
// A non required validated path.
$form['optional_validate'] = array(
'#type' => 'path',
'#required' => FALSE,
'#title' => 'optional_validate',
'#convert_path' => PathElement::CONVERT_NONE,
);
// A non required converted path.
$form['optional_validate'] = array(
'#type' => 'path',
'#required' => FALSE,
'#title' => 'optional_validate',
'#convert_path' => PathElement::CONVERT_ROUTE,
);
// A converted required validated path.
$form['required_validate_route'] = array(
'#type' => 'path',
'#required' => TRUE,
'#title' => 'required_validate_route',
);
// A converted required validated path.
$form['required_validate_url'] = array(
'#type' => 'path',
'#required' => TRUE,
'#title' => 'required_validate_url',
'#convert_path' => PathElement::CONVERT_URL,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
);
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {}
/**
* Form validation handler.
*
* @param array $form
* An associative array containing the structure of the form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*/
public function validateForm(array &$form, FormStateInterface $form_state) {}
/**
* Tests that default handlers are added even if custom are specified.
*/
public function testPathElement() {
$form_state = new FormState(array(
'values' => array(
'required_validate' => 'user/' . $this->testUser->id(),
'required_non_validate' => 'magic-ponies',
'required_validate_route' => 'user/' . $this->testUser->id(),
'required_validate_url' => 'user/' . $this->testUser->id(),
),
));
$form_builder = $this->container->get('form_builder');
$form_builder->submitForm($this, $form_state);
// Valid form state.
$this->assertEqual(count($form_state->getErrors()), 0);
$this->assertEqual($form_state->getValue('required_validate_route'), array(
'route_name' => 'entity.user.canonical',
'route_parameters' => array(
'user' => $this->testUser->id(),
),
));
/** @var \Drupal\Core\Url $url */
$url = $form_state->getValue('required_validate_url');
$this->assertTrue($url instanceof Url);
$this->assertEqual($url->getRouteName(), 'entity.user.canonical');
$this->assertEqual($url->getRouteParameters(), array(
'user' => $this->testUser->id(),
));
// Test #required.
$form_state = new FormState(array(
'values' => array(
'required_non_validate' => 'magic-ponies',
'required_validate_route' => 'user/' . $this->testUser->id(),
'required_validate_url' => 'user/' . $this->testUser->id(),
),
));
$form_builder->submitForm($this, $form_state);
$errors = $form_state->getErrors();
// Should be missing 'required_validate' field.
$this->assertEqual(count($errors), 1);
$this->assertEqual($errors, array('required_validate' => t('!name field is required.', array('!name' => 'required_validate'))));
// Test invalid parameters.
$form_state = new FormState(array(
'values' => array(
'required_validate' => 'user/74',
'required_non_validate' => 'magic-ponies',
'required_validate_route' => 'user/74',
'required_validate_url' => 'user/74',
),
));
$form_builder = $this->container->get('form_builder');
$form_builder->submitForm($this, $form_state);
// Valid form state.
$errors = $form_state->getErrors();
$this->assertEqual(count($errors), 3);
$this->assertEqual($errors, array(
'required_validate' => t('This path does not exist or you do not have permission to link to %path.', array('%path' => 'user/74')),
'required_validate_route' => t('This path does not exist or you do not have permission to link to %path.', array('%path' => 'user/74')),
'required_validate_url' => t('This path does not exist or you do not have permission to link to %path.', array('%path' => 'user/74')),
));
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment