>
>:
diff --git a/core/modules/field_ui/field_ui-rtl.css b/core/modules/field_ui/field_ui.admin-rtl.css
similarity index 100%
rename from core/modules/field_ui/field_ui-rtl.css
rename to core/modules/field_ui/field_ui.admin-rtl.css
diff --git a/core/modules/field_ui/field_ui.css b/core/modules/field_ui/field_ui.admin.css
similarity index 88%
rename from core/modules/field_ui/field_ui.css
rename to core/modules/field_ui/field_ui.admin.css
index ae469e2..c439640 100644
--- a/core/modules/field_ui/field_ui.css
+++ b/core/modules/field_ui/field_ui.admin.css
@@ -2,7 +2,7 @@
* @file
* Stylesheet for the Field UI module.
*/
-
+
/* 'Manage fields' and 'Manage display' overviews */
table.field-ui-overview tr.add-new .label-input {
float: left; /* LTR */
@@ -12,6 +12,10 @@ table.field-ui-overview tr.add-new .tabledrag-changed {
}
table.field-ui-overview tr.add-new .description {
margin-bottom: 0;
+ max-width: 250px;
+}
+table.field-ui-overview tr.add-new .form-type-machine-name .description {
+ white-space: normal;
}
table.field-ui-overview tr.add-new .add-new-placeholder {
font-weight: bold;
@@ -29,6 +33,10 @@ table.field-ui-overview tr.region-populated {
table.field-ui-overview tr.region-add-new-title {
display: none;
}
+table.field-ui-overview tr.add-new td {
+ vertical-align: top;
+ white-space: nowrap;
+}
/* 'Manage display' overview */
#field-display-overview .field-formatter-summary-cell {
diff --git a/core/modules/field_ui/field_ui.admin.inc b/core/modules/field_ui/field_ui.admin.inc
index cec0d84..c22fe21 100644
--- a/core/modules/field_ui/field_ui.admin.inc
+++ b/core/modules/field_ui/field_ui.admin.inc
@@ -324,7 +324,7 @@ function field_ui_field_overview_form($form, &$form_state, $entity_type, $bundle
t('Label'),
t('Weight'),
t('Parent'),
- t('Name'),
+ t('Machine name'),
t('Field'),
t('Widget'),
array('data' => t('Operations'), 'colspan' => 2),
@@ -506,16 +506,24 @@ function field_ui_field_overview_form($form, &$form_state, $entity_type, $bundle
),
),
'field_name' => array(
- '#type' => 'textfield',
+ '#type' => 'machine_name',
'#title' => t('New field name'),
'#title_display' => 'invisible',
// This field should stay LTR even for RTL languages.
'#field_prefix' => '
field_',
'#field_suffix' => '',
- '#attributes' => array('dir'=>'ltr'),
- '#size' => 10,
- '#description' => t('Field name (a-z, 0-9, _)'),
+ '#size' => 15,
+ '#description' => t('A unique machine-readable name containing letters, numbers, and underscores.'),
+ // 32 characters minus the 'field_' prefix.
+ '#maxlength' => 26,
'#prefix' => '
',
+ '#machine_name' => array(
+ 'source' => array('fields', $name, 'label'),
+ 'exists' => '_field_ui_field_name_exists',
+ 'standalone' => TRUE,
+ 'label' => '',
+ ),
+ '#required' => FALSE,
),
'type' => array(
'#type' => 'select',
@@ -631,7 +639,7 @@ function field_ui_field_overview_form($form, &$form_state, $entity_type, $bundle
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save'));
- $form['#attached']['css'][] = drupal_get_path('module', 'field_ui') . '/field_ui.css';
+ $form['#attached']['css'][] = drupal_get_path('module', 'field_ui') . '/field_ui.admin.css';
$form['#attached']['js'][] = drupal_get_path('module', 'field_ui') . '/field_ui.js';
// Add settings for the update selects behavior.
@@ -686,25 +694,8 @@ function _field_ui_field_overview_form_validate_add_new($form, &$form_state) {
$field_name = $field['field_name'];
// Add the 'field_' prefix.
- if (substr($field_name, 0, 6) != 'field_') {
- $field_name = 'field_' . $field_name;
- form_set_value($form['fields']['_add_new_field']['field_name'], $field_name, $form_state);
- }
-
- // Invalid field name.
- if (!preg_match('!^field_[a-z0-9_]+$!', $field_name)) {
- form_set_error('fields][_add_new_field][field_name', t('Add new field: the field name %field_name is invalid. The name must include only lowercase unaccentuated letters, numbers, and underscores.', array('%field_name' => $field_name)));
- }
- if (strlen($field_name) > 32) {
- form_set_error('fields][_add_new_field][field_name', t("Add new field: the field name %field_name is too long. The name is limited to 32 characters, including the 'field_' prefix.", array('%field_name' => $field_name)));
- }
-
- // Field name already exists. We need to check inactive fields as well, so
- // we can't use field_info_fields().
- $fields = field_read_fields(array('field_name' => $field_name), array('include_inactive' => TRUE));
- if ($fields) {
- form_set_error('fields][_add_new_field][field_name', t('Add new field: the field name %field_name already exists.', array('%field_name' => $field_name)));
- }
+ $field_name = 'field_' . $field_name;
+ form_set_value($form['fields']['_add_new_field']['field_name'], $field_name, $form_state);
}
// Missing field type.
@@ -727,6 +718,24 @@ function _field_ui_field_overview_form_validate_add_new($form, &$form_state) {
}
/**
+ * Render API callback: Checks if a field machine name is taken.
+ *
+ * @param $value
+ * The machine name, not prefixed with 'field_'.
+ *
+ * @return
+ * Whether or not the field machine name is taken.
+ */
+function _field_ui_field_name_exists($value) {
+ // Prefix with 'field_'.
+ $field_name = 'field_' . $value;
+
+ // We need to check inactive fields as well, so we can't use
+ // field_info_fields().
+ return (bool) field_read_fields(array('field_name' => $field_name), array('include_inactive' => TRUE));
+}
+
+/**
* Validates the 'add existing field' row of field_ui_field_overview_form().
*
* @see field_ui_field_overview_form_validate()
@@ -1219,7 +1228,7 @@ function field_ui_display_overview_form($form, &$form_state, $entity_type, $bund
$form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save'));
$form['#attached']['js'][] = drupal_get_path('module', 'field_ui') . '/field_ui.js';
- $form['#attached']['css'][] = drupal_get_path('module', 'field_ui') . '/field_ui.css';
+ $form['#attached']['css'][] = drupal_get_path('module', 'field_ui') . '/field_ui.admin.css';
// Add tabledrag behavior.
$form['#attached']['drupal_add_tabledrag'][] = array('field-display-overview', 'order', 'sibling', 'field-weight');
@@ -2026,7 +2035,7 @@ function field_ui_default_value_widget($field, $instance, &$form, &$form_state)
$instance['description'] = '';
// @todo Allow multiple values (requires more work on 'add more' JS handler).
- $element += field_default_form($instance['entity_type'], NULL, $field, $instance, LANGUAGE_NONE, $items, $element, $form_state, 0);
+ $element += field_default_form($instance['entity_type'], NULL, $field, $instance, LANGUAGE_NOT_SPECIFIED, $items, $element, $form_state, 0);
return $element;
}
@@ -2045,25 +2054,25 @@ function field_ui_field_edit_form_validate($form, &$form_state) {
if (isset($form['instance']['default_value_widget'])) {
$element = $form['instance']['default_value_widget'];
- $field_state = field_form_get_state($element['#parents'], $field_name, LANGUAGE_NONE, $form_state);
+ $field_state = field_form_get_state($element['#parents'], $field_name, LANGUAGE_NOT_SPECIFIED, $form_state);
$field = $field_state['field'];
// Extract the 'default value'.
$items = array();
- field_default_extract_form_values(NULL, NULL, $field, $instance, LANGUAGE_NONE, $items, $element, $form_state);
+ field_default_extract_form_values(NULL, NULL, $field, $instance, LANGUAGE_NOT_SPECIFIED, $items, $element, $form_state);
// Validate the value and report errors.
$errors = array();
$function = $field['module'] . '_field_validate';
if (function_exists($function)) {
- $function(NULL, NULL, $field, $instance, LANGUAGE_NONE, $items, $errors);
+ $function(NULL, NULL, $field, $instance, LANGUAGE_NOT_SPECIFIED, $items, $errors);
}
- if (isset($errors[$field_name][LANGUAGE_NONE])) {
+ if (isset($errors[$field_name][LANGUAGE_NOT_SPECIFIED])) {
// Store reported errors in $form_state.
- $field_state['errors'] = $errors[$field_name][LANGUAGE_NONE];
- field_form_set_state($element['#parents'], $field_name, LANGUAGE_NONE, $form_state, $field_state);
+ $field_state['errors'] = $errors[$field_name][LANGUAGE_NOT_SPECIFIED];
+ field_form_set_state($element['#parents'], $field_name, LANGUAGE_NOT_SPECIFIED, $form_state, $field_state);
// Assign reported errors to the correct form element.
- field_default_form_errors(NULL, NULL, $field, $instance, LANGUAGE_NONE, $items, $element, $form_state);
+ field_default_form_errors(NULL, NULL, $field, $instance, LANGUAGE_NOT_SPECIFIED, $items, $element, $form_state);
}
}
}
@@ -2094,8 +2103,8 @@ function field_ui_field_edit_form_submit($form, &$form_state) {
// Extract field values.
$items = array();
- field_default_extract_form_values(NULL, NULL, $field, $instance, LANGUAGE_NONE, $items, $element, $form_state);
- field_default_submit(NULL, NULL, $field, $instance, LANGUAGE_NONE, $items, $element, $form_state);
+ field_default_extract_form_values(NULL, NULL, $field, $instance, LANGUAGE_NOT_SPECIFIED, $items, $element, $form_state);
+ field_default_submit(NULL, NULL, $field, $instance, LANGUAGE_NOT_SPECIFIED, $items, $element, $form_state);
$instance['default_value'] = $items ? $items : NULL;
}
diff --git a/core/modules/field_ui/field_ui.api.php b/core/modules/field_ui/field_ui.api.php
index f903e12..882f467 100644
--- a/core/modules/field_ui/field_ui.api.php
+++ b/core/modules/field_ui/field_ui.api.php
@@ -6,7 +6,7 @@
*/
/**
- * @ingroup field_ui_field_type
+ * @addtogroup field_types
* @{
*/
@@ -200,5 +200,5 @@ function hook_field_formatter_settings_summary($field, $instance, $view_mode) {
}
/**
- * @} End of "ingroup field_ui_field_type"
+ * @} End of "addtogroup field_types"
*/
diff --git a/core/modules/field_ui/field_ui.test b/core/modules/field_ui/field_ui.test
index c2e3a98..8c202e5 100644
--- a/core/modules/field_ui/field_ui.test
+++ b/core/modules/field_ui/field_ui.test
@@ -137,8 +137,6 @@ class FieldUITestCase extends DrupalWebTestCase {
* Tests the functionality of the 'Manage fields' screen.
*/
class FieldUIManageFieldsTestCase extends FieldUITestCase {
- protected $profile = 'testing';
-
public static function getInfo() {
return array(
'name' => 'Manage fields',
@@ -163,6 +161,7 @@ class FieldUIManageFieldsTestCase extends FieldUITestCase {
$vocabulary = (object) array(
'name' => 'Tags',
'machine_name' => 'tags',
+ 'langcode' => LANGUAGE_NOT_SPECIFIED,
);
taxonomy_vocabulary_save($vocabulary);
@@ -202,7 +201,7 @@ class FieldUIManageFieldsTestCase extends FieldUITestCase {
// Check all table columns.
$table_headers = array(
t('Label'),
- t('Name'),
+ t('Machine name'),
t('Field'),
t('Widget'),
t('Operations'),
@@ -328,7 +327,7 @@ class FieldUIManageFieldsTestCase extends FieldUITestCase {
);
field_create_instance($instance);
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$admin_path = 'admin/structure/types/manage/' . $this->hyphen_type . '/fields/' . $field_name;
$element_id = "edit-$field_name-$langcode-0-value";
$element_name = "{$field_name}[$langcode][0][value]";
@@ -368,7 +367,7 @@ class FieldUIManageFieldsTestCase extends FieldUITestCase {
$bundle_path1 = 'admin/structure/types/manage/' . $this->hyphen_type;
$edit1 = array(
'fields[_add_new_field][label]' => $this->field_label,
- 'fields[_add_new_field][field_name]' => $this->field_name,
+ 'fields[_add_new_field][field_name]' => $this->field_name_input,
);
$this->fieldUIAddNewField($bundle_path1, $edit1);
@@ -456,6 +455,25 @@ class FieldUIManageFieldsTestCase extends FieldUITestCase {
$this->drupalGet('admin/structure/types/manage/' . $hyphen_type2 . '/fields');
}
+
+ /**
+ * Tests that a duplicate field name is caught by validation.
+ */
+ function testDuplicateFieldName() {
+ // field_tags already exists, so we're expecting an error when trying to
+ // create a new field with the same name.
+ $edit = array(
+ 'fields[_add_new_field][field_name]' => 'tags',
+ 'fields[_add_new_field][label]' => $this->randomName(),
+ 'fields[_add_new_field][type]' => 'taxonomy_term_reference',
+ 'fields[_add_new_field][widget_type]' => 'options_select',
+ );
+ $url = 'admin/structure/types/manage/' . $this->hyphen_type . '/fields';
+ $this->drupalPost($url, $edit, t('Save'));
+
+ $this->assertText(t('The machine-readable name is already in use. It must be unique.'));
+ $this->assertUrl($url, array(), 'Stayed on the same page.');
+ }
}
/**
@@ -484,7 +502,7 @@ class FieldUIManageDisplayTestCase extends FieldUITestCase {
// Create a field, and a node with some data for the field.
$edit = array(
'fields[_add_new_field][label]' => 'Test field',
- 'fields[_add_new_field][field_name]' => 'field_test',
+ 'fields[_add_new_field][field_name]' => 'test',
);
$this->fieldUIAddNewField($manage_fields, $edit);
@@ -529,7 +547,7 @@ class FieldUIManageDisplayTestCase extends FieldUITestCase {
// Create a field, and a node with some data for the field.
$edit = array(
'fields[_add_new_field][label]' => 'Test field',
- 'fields[_add_new_field][field_name]' => 'field_test',
+ 'fields[_add_new_field][field_name]' => 'test',
);
$this->fieldUIAddNewField('admin/structure/types/manage/' . $this->hyphen_type, $edit);
// For this test, use a formatter setting value that is an integer unlikely
@@ -538,7 +556,7 @@ class FieldUIManageDisplayTestCase extends FieldUITestCase {
$value = 12345;
$settings = array(
'type' => $this->type,
- 'field_test' => array(LANGUAGE_NONE => array(array('value' => $value))),
+ 'field_test' => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => $value))),
);
$node = $this->drupalCreateNode($settings);
@@ -690,7 +708,11 @@ class FieldUIAlterTestCase extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp(array('field_test'));
+ parent::setUp(array('field_ui', 'field_test', 'text', 'list'));
+
+ // Create Article node type.
+ $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
+ $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
// Create test user.
$admin_user = $this->drupalCreateUser(array('access content', 'administer content types', 'administer users'));
diff --git a/core/modules/file/tests/file.test b/core/modules/file/tests/file.test
index 459609b..05083fc 100644
--- a/core/modules/file/tests/file.test
+++ b/core/modules/file/tests/file.test
@@ -9,6 +9,8 @@
* Provides methods specifically for testing File module's field handling.
*/
class FileFieldTestCase extends DrupalWebTestCase {
+ protected $profile = 'standard';
+
protected $admin_user;
function setUp() {
@@ -122,7 +124,7 @@ class FileFieldTestCase extends DrupalWebTestCase {
* Uploads a file to a node.
*/
function uploadNodeFile($file, $field_name, $nid_or_type, $new_revision = TRUE, $extras = array()) {
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$edit = array(
"title" => $this->randomName(),
'revision' => (string) (int) $new_revision,
@@ -168,7 +170,7 @@ class FileFieldTestCase extends DrupalWebTestCase {
*/
function replaceNodeFile($file, $field_name, $nid, $new_revision = TRUE) {
$edit = array(
- 'files[' . $field_name . '_' . LANGUAGE_NONE . '_0]' => drupal_realpath($file->uri),
+ 'files[' . $field_name . '_' . LANGUAGE_NOT_SPECIFIED . '_0]' => drupal_realpath($file->uri),
'revision' => (string) (int) $new_revision,
);
@@ -349,7 +351,7 @@ class FileFieldWidgetTestCase extends FileFieldTestCase {
// does not yet support file uploads.
$nid = $this->uploadNodeFile($test_file, $field_name, $type_name);
$node = node_load($nid, NULL, TRUE);
- $node_file = (object) $node->{$field_name}[LANGUAGE_NONE][0];
+ $node_file = (object) $node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0];
$this->assertFileExists($node_file, t('New file saved to disk on node creation.'));
// Ensure the file can be downloaded.
@@ -379,7 +381,7 @@ class FileFieldWidgetTestCase extends FileFieldTestCase {
// Save the node and ensure it does not have the file.
$this->drupalPost(NULL, array(), t('Save'));
$node = node_load($nid, NULL, TRUE);
- $this->assertTrue(empty($node->{$field_name}[LANGUAGE_NONE][0]['fid']), t('File was successfully removed from the node.'));
+ $this->assertTrue(empty($node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0]['fid']), t('File was successfully removed from the node.'));
}
}
@@ -417,7 +419,7 @@ class FileFieldWidgetTestCase extends FileFieldTestCase {
$this->drupalGet("node/add/$type_name");
foreach (array($field_name2, $field_name) as $each_field_name) {
for ($delta = 0; $delta < 3; $delta++) {
- $edit = array('files[' . $each_field_name . '_' . LANGUAGE_NONE . '_' . $delta . ']' => drupal_realpath($test_file->uri));
+ $edit = array('files[' . $each_field_name . '_' . LANGUAGE_NOT_SPECIFIED . '_' . $delta . ']' => drupal_realpath($test_file->uri));
// If the Upload button doesn't exist, drupalPost() will automatically
// fail with an assertion message.
$this->drupalPost(NULL, $edit, t('Upload'));
@@ -448,11 +450,11 @@ class FileFieldWidgetTestCase extends FileFieldTestCase {
$check_field_name = $field_name;
}
- $this->assertIdentical((string) $button['name'], $check_field_name . '_' . LANGUAGE_NONE . '_' . $key. '_remove_button');
+ $this->assertIdentical((string) $button['name'], $check_field_name . '_' . LANGUAGE_NOT_SPECIFIED . '_' . $key. '_remove_button');
}
// "Click" the remove button (emulating either a nojs or js submission).
- $button_name = $current_field_name . '_' . LANGUAGE_NONE . '_' . $delta . '_remove_button';
+ $button_name = $current_field_name . '_' . LANGUAGE_NOT_SPECIFIED . '_' . $delta . '_remove_button';
switch ($type) {
case 'nojs':
// drupalPost() takes a $submit parameter that is the value of the
@@ -480,7 +482,7 @@ class FileFieldWidgetTestCase extends FileFieldTestCase {
// Ensure an "Upload" button for the current field is displayed with the
// correct name.
- $upload_button_name = $current_field_name . '_' . LANGUAGE_NONE . '_' . $remaining . '_upload_button';
+ $upload_button_name = $current_field_name . '_' . LANGUAGE_NOT_SPECIFIED . '_' . $remaining . '_upload_button';
$buttons = $this->xpath('//input[@type="submit" and @value="Upload" and @name=:name]', array(':name' => $upload_button_name));
$this->assertTrue(is_array($buttons) && count($buttons) == 1, t('The upload button is displayed with the correct name (JSMode=%type).', array('%type' => $type)));
@@ -500,7 +502,7 @@ class FileFieldWidgetTestCase extends FileFieldTestCase {
preg_match('/node\/([0-9]+)/', $this->getUrl(), $matches);
$nid = $matches[1];
$node = node_load($nid, NULL, TRUE);
- $this->assertTrue(empty($node->{$field_name}[LANGUAGE_NONE][0]['fid']), t('Node was successfully saved without any files.'));
+ $this->assertTrue(empty($node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0]['fid']), t('Node was successfully saved without any files.'));
}
}
@@ -525,7 +527,7 @@ class FileFieldWidgetTestCase extends FileFieldTestCase {
$this->drupalPost("admin/structure/types/manage/$type_name/fields/$field_name", $edit, t('Save settings'));
$nid = $this->uploadNodeFile($test_file, $field_name, $type_name);
$node = node_load($nid, NULL, TRUE);
- $node_file = (object) $node->{$field_name}[LANGUAGE_NONE][0];
+ $node_file = (object) $node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0];
$this->assertFileExists($node_file, t('New file saved to disk on node creation.'));
// Ensure the private file is available to the user who uploaded it.
@@ -578,8 +580,8 @@ class FileFieldWidgetTestCase extends FileFieldTestCase {
// Add a comment with a file.
$text_file = $this->getTestFile('text');
$edit = array(
- 'files[field_' . $name . '_' . LANGUAGE_NONE . '_' . 0 . ']' => drupal_realpath($text_file->uri),
- 'comment_body[' . LANGUAGE_NONE . '][0][value]' => $comment_body = $this->randomName(),
+ 'files[field_' . $name . '_' . LANGUAGE_NOT_SPECIFIED . '_' . 0 . ']' => drupal_realpath($text_file->uri),
+ 'comment_body[' . LANGUAGE_NOT_SPECIFIED . '][0][value]' => $comment_body = $this->randomName(),
);
$this->drupalPost(NULL, $edit, t('Save'));
@@ -591,7 +593,7 @@ class FileFieldWidgetTestCase extends FileFieldTestCase {
$this->drupalLogin($user);
$comment = comment_load($cid);
- $comment_file = (object) $comment->{'field_' . $name}[LANGUAGE_NONE][0];
+ $comment_file = (object) $comment->{'field_' . $name}[LANGUAGE_NOT_SPECIFIED][0];
$this->assertFileExists($comment_file, t('New file saved to disk on node creation.'));
// Test authenticated file download.
$url = file_create_url($comment_file->uri);
@@ -659,7 +661,7 @@ class FileFieldRevisionTestCase extends FileFieldTestCase {
// Check that the file exists on disk and in the database.
$node = node_load($nid, NULL, TRUE);
- $node_file_r1 = (object) $node->{$field_name}[LANGUAGE_NONE][0];
+ $node_file_r1 = (object) $node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0];
$node_vid_r1 = $node->vid;
$this->assertFileExists($node_file_r1, t('New file saved to disk on node creation.'));
$this->assertFileEntryExists($node_file_r1, t('File entry exists in database on node creation.'));
@@ -668,7 +670,7 @@ class FileFieldRevisionTestCase extends FileFieldTestCase {
// Upload another file to the same node in a new revision.
$this->replaceNodeFile($test_file, $field_name, $nid);
$node = node_load($nid, NULL, TRUE);
- $node_file_r2 = (object) $node->{$field_name}[LANGUAGE_NONE][0];
+ $node_file_r2 = (object) $node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0];
$node_vid_r2 = $node->vid;
$this->assertFileExists($node_file_r2, t('Replacement file exists on disk after creating new revision.'));
$this->assertFileEntryExists($node_file_r2, t('Replacement file entry exists in database after creating new revision.'));
@@ -676,7 +678,7 @@ class FileFieldRevisionTestCase extends FileFieldTestCase {
// Check that the original file is still in place on the first revision.
$node = node_load($nid, $node_vid_r1, TRUE);
- $this->assertEqual($node_file_r1, (object) $node->{$field_name}[LANGUAGE_NONE][0], t('Original file still in place after replacing file in new revision.'));
+ $this->assertEqual($node_file_r1, (object) $node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0], t('Original file still in place after replacing file in new revision.'));
$this->assertFileExists($node_file_r1, t('Original file still in place after replacing file in new revision.'));
$this->assertFileEntryExists($node_file_r1, t('Original file entry still in place after replacing file in new revision'));
$this->assertFileIsPermanent($node_file_r1, t('Original file is still permanent.'));
@@ -685,7 +687,7 @@ class FileFieldRevisionTestCase extends FileFieldTestCase {
// Check that the file is still the same as the previous revision.
$this->drupalPost('node/' . $nid . '/edit', array('revision' => '1'), t('Save'));
$node = node_load($nid, NULL, TRUE);
- $node_file_r3 = (object) $node->{$field_name}[LANGUAGE_NONE][0];
+ $node_file_r3 = (object) $node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0];
$node_vid_r3 = $node->vid;
$this->assertEqual($node_file_r2, $node_file_r3, t('Previous revision file still in place after creating a new revision without a new file.'));
$this->assertFileIsPermanent($node_file_r3, t('New revision file is permanent.'));
@@ -693,7 +695,7 @@ class FileFieldRevisionTestCase extends FileFieldTestCase {
// Revert to the first revision and check that the original file is active.
$this->drupalPost('node/' . $nid . '/revisions/' . $node_vid_r1 . '/revert', array(), t('Revert'));
$node = node_load($nid, NULL, TRUE);
- $node_file_r4 = (object) $node->{$field_name}[LANGUAGE_NONE][0];
+ $node_file_r4 = (object) $node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0];
$node_vid_r4 = $node->vid;
$this->assertEqual($node_file_r1, $node_file_r4, t('Original revision file still in place after reverting to the original revision.'));
$this->assertFileIsPermanent($node_file_r4, t('Original revision file still permanent after reverting to the original revision.'));
@@ -708,7 +710,7 @@ class FileFieldRevisionTestCase extends FileFieldTestCase {
// Attach the second file to a user.
$user = $this->drupalCreateUser();
$edit = (array) $user;
- $edit[$field_name][LANGUAGE_NONE][0] = (array) $node_file_r3;
+ $edit[$field_name][LANGUAGE_NOT_SPECIFIED][0] = (array) $node_file_r3;
user_save($user, $edit);
$this->drupalGet('user/' . $user->uid . '/edit');
@@ -785,12 +787,12 @@ class FileFieldDisplayTestCase extends FileFieldTestCase {
// Check that the default formatter is displaying with the file name.
$node = node_load($nid, NULL, TRUE);
- $node_file = (object) $node->{$field_name}[LANGUAGE_NONE][0];
+ $node_file = (object) $node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0];
$default_output = theme('file_link', array('file' => $node_file));
$this->assertRaw($default_output, t('Default formatter displaying correctly on full node view.'));
// Turn the "display" option off and check that the file is no longer displayed.
- $edit = array($field_name . '[' . LANGUAGE_NONE . '][0][display]' => FALSE);
+ $edit = array($field_name . '[' . LANGUAGE_NOT_SPECIFIED . '][0][display]' => FALSE);
$this->drupalPost('node/' . $nid . '/edit', $edit, t('Save'));
$this->assertNoRaw($default_output, t('Field is hidden when "display" option is unchecked.'));
@@ -826,7 +828,7 @@ class FileFieldValidateTestCase extends FileFieldTestCase {
$test_file = $this->getTestFile('text');
// Try to post a new node without uploading a file.
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$edit = array("title" => $this->randomName());
$this->drupalPost('node/add/' . $type_name, $edit, t('Save'));
$this->assertRaw(t('!title field is required.', array('!title' => $instance['label'])), t('Node save failed when required file field was empty.'));
@@ -837,7 +839,7 @@ class FileFieldValidateTestCase extends FileFieldTestCase {
$node = node_load($nid, NULL, TRUE);
- $node_file = (object) $node->{$field_name}[LANGUAGE_NONE][0];
+ $node_file = (object) $node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0];
$this->assertFileExists($node_file, t('File exists after uploading to the required field.'));
$this->assertFileEntryExists($node_file, t('File entry exists after uploading to the required field.'));
@@ -853,7 +855,7 @@ class FileFieldValidateTestCase extends FileFieldTestCase {
// Create a new node with the uploaded file into the multivalue field.
$nid = $this->uploadNodeFile($test_file, $field_name, $type_name);
$node = node_load($nid, NULL, TRUE);
- $node_file = (object) $node->{$field_name}[LANGUAGE_NONE][0];
+ $node_file = (object) $node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0];
$this->assertFileExists($node_file, t('File exists after uploading to the required multiple value field.'));
$this->assertFileEntryExists($node_file, t('File entry exists after uploading to the required multipel value field.'));
@@ -889,7 +891,7 @@ class FileFieldValidateTestCase extends FileFieldTestCase {
// Create a new node with the small file, which should pass.
$nid = $this->uploadNodeFile($small_file, $field_name, $type_name);
$node = node_load($nid, NULL, TRUE);
- $node_file = (object) $node->{$field_name}[LANGUAGE_NONE][0];
+ $node_file = (object) $node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0];
$this->assertFileExists($node_file, t('File exists after uploading a file (%filesize) under the max limit (%maxsize).', array('%filesize' => format_size($small_file->filesize), '%maxsize' => $max_filesize)));
$this->assertFileEntryExists($node_file, t('File entry exists after uploading a file (%filesize) under the max limit (%maxsize).', array('%filesize' => format_size($small_file->filesize), '%maxsize' => $max_filesize)));
@@ -905,7 +907,7 @@ class FileFieldValidateTestCase extends FileFieldTestCase {
// Upload the big file successfully.
$nid = $this->uploadNodeFile($large_file, $field_name, $type_name);
$node = node_load($nid, NULL, TRUE);
- $node_file = (object) $node->{$field_name}[LANGUAGE_NONE][0];
+ $node_file = (object) $node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0];
$this->assertFileExists($node_file, t('File exists after uploading a file (%filesize) with no max limit.', array('%filesize' => format_size($large_file->filesize))));
$this->assertFileEntryExists($node_file, t('File entry exists after uploading a file (%filesize) with no max limit.', array('%filesize' => format_size($large_file->filesize))));
@@ -932,7 +934,7 @@ class FileFieldValidateTestCase extends FileFieldTestCase {
// Check that the file can be uploaded with no extension checking.
$nid = $this->uploadNodeFile($test_file, $field_name, $type_name);
$node = node_load($nid, NULL, TRUE);
- $node_file = (object) $node->{$field_name}[LANGUAGE_NONE][0];
+ $node_file = (object) $node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0];
$this->assertFileExists($node_file, t('File exists after uploading a file with no extension checking.'));
$this->assertFileEntryExists($node_file, t('File entry exists after uploading a file with no extension checking.'));
@@ -950,7 +952,7 @@ class FileFieldValidateTestCase extends FileFieldTestCase {
// Check that the file can be uploaded with extension checking.
$nid = $this->uploadNodeFile($test_file, $field_name, $type_name);
$node = node_load($nid, NULL, TRUE);
- $node_file = (object) $node->{$field_name}[LANGUAGE_NONE][0];
+ $node_file = (object) $node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0];
$this->assertFileExists($node_file, t('File exists after uploading a file with extension checking.'));
$this->assertFileEntryExists($node_file, t('File entry exists after uploading a file with extension checking.'));
@@ -985,7 +987,7 @@ class FileFieldPathTestCase extends FileFieldTestCase {
// Check that the file was uploaded to the file root.
$node = node_load($nid, NULL, TRUE);
- $node_file = (object) $node->{$field_name}[LANGUAGE_NONE][0];
+ $node_file = (object) $node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0];
$this->assertPathMatch('public://' . $test_file->filename, $node_file->uri, t('The file %file was uploaded to the correct path.', array('%file' => $node_file->uri)));
// Change the path to contain multiple subdirectories.
@@ -996,7 +998,7 @@ class FileFieldPathTestCase extends FileFieldTestCase {
// Check that the file was uploaded into the subdirectory.
$node = node_load($nid, NULL, TRUE);
- $node_file = (object) $node->{$field_name}[LANGUAGE_NONE][0];
+ $node_file = (object) $node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0];
$this->assertPathMatch('public://foo/bar/baz/' . $test_file->filename, $node_file->uri, t('The file %file was uploaded to the correct path.', array('%file' => $node_file->uri)));
// Check the path when used with tokens.
@@ -1008,7 +1010,7 @@ class FileFieldPathTestCase extends FileFieldTestCase {
// Check that the file was uploaded into the subdirectory.
$node = node_load($nid, NULL, TRUE);
- $node_file = (object) $node->{$field_name}[LANGUAGE_NONE][0];
+ $node_file = (object) $node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0];
// Do token replacement using the same user which uploaded the file, not
// the user running the test case.
$data = array('user' => $this->admin_user);
@@ -1078,7 +1080,7 @@ class FileTokenReplaceTestCase extends FileFieldTestCase {
// Load the node and the file.
$node = node_load($nid, NULL, TRUE);
- $file = file_load($node->{$field_name}[LANGUAGE_NONE][0]['fid']);
+ $file = file_load($node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0]['fid']);
// Generate and test sanitized tokens.
$tests = array();
@@ -1147,7 +1149,7 @@ class FilePrivateTestCase extends FileFieldTestCase {
$test_file = $this->getTestFile('text');
$nid = $this->uploadNodeFile($test_file, $field_name, $type_name, TRUE, array('private' => TRUE));
$node = node_load($nid, NULL, TRUE);
- $node_file = (object) $node->{$field_name}[LANGUAGE_NONE][0];
+ $node_file = (object) $node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0];
// Ensure the file can be downloaded.
$this->drupalGet(file_create_url($node_file->uri));
$this->assertResponse(200, t('Confirmed that the generated URL is correct by downloading the shipped file.'));
diff --git a/core/modules/filter/filter.module b/core/modules/filter/filter.module
index 77f63ef..b4e09a5 100644
--- a/core/modules/filter/filter.module
+++ b/core/modules/filter/filter.module
@@ -215,9 +215,11 @@ function filter_format_save($format) {
}
$filter_info = filter_get_filters();
foreach ($filter_info as $name => $filter) {
- // Add new filters without weight to the bottom.
+ // If the format does not specify an explicit weight for a filter, assign
+ // a default weight, either defined in hook_filter_info(), or the default of
+ // 0 by filter_get_filters().
if (!isset($format->filters[$name]['weight'])) {
- $format->filters[$name]['weight'] = 10;
+ $format->filters[$name]['weight'] = $filter['weight'];
}
$format->filters[$name]['status'] = isset($format->filters[$name]['status']) ? $format->filters[$name]['status'] : 0;
$format->filters[$name]['module'] = $filter['module'];
@@ -916,7 +918,7 @@ function filter_process_format($element) {
$element['value']['#rows'] = 3;
}
$element['value']['#disabled'] = TRUE;
- $element['value']['#resizable'] = FALSE;
+ $element['value']['#resizable'] = 'none';
// Hide the text format selector and any other child element (such as text
// field's summary).
diff --git a/core/modules/filter/filter.test b/core/modules/filter/filter.test
index 2bafd47..8226054 100644
--- a/core/modules/filter/filter.test
+++ b/core/modules/filter/filter.test
@@ -161,6 +161,8 @@ class FilterCRUDTestCase extends DrupalWebTestCase {
}
class FilterAdminTestCase extends DrupalWebTestCase {
+ protected $profile = 'standard';
+
public static function getInfo() {
return array(
'name' => 'Filter administration functionality',
@@ -353,7 +355,7 @@ class FilterAdminTestCase extends DrupalWebTestCase {
$text = $body . '
' . $extra_text . '';
$edit = array();
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$edit["title"] = $this->randomName();
$edit["body[$langcode][0][value]"] = $text;
$edit["body[$langcode][0][format]"] = $filtered;
@@ -419,6 +421,8 @@ class FilterFormatAccessTestCase extends DrupalWebTestCase {
function setUp() {
parent::setUp();
+ $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
+
// Create a user who can administer text formats, but does not have
// specific permission to use any of them.
$this->filter_admin_user = $this->drupalCreateUser(array(
@@ -481,7 +485,7 @@ class FilterFormatAccessTestCase extends DrupalWebTestCase {
// the disallowed format does not.
$this->drupalLogin($this->web_user);
$this->drupalGet('node/add/page');
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$elements = $this->xpath('//select[@name=:name]/option', array(
':name' => "body[$langcode][0][format]",
':option' => $this->allowed_format->format,
@@ -525,7 +529,7 @@ class FilterFormatAccessTestCase extends DrupalWebTestCase {
* forced to choose a new format before saving the page.
*/
function testFormatWidgetPermissions() {
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$title_key = "title";
$body_value_key = "body[$langcode][0][value]";
$body_format_key = "body[$langcode][0][format]";
@@ -739,7 +743,22 @@ class FilterSecurityTestCase extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('php', 'filter_test');
+ parent::setUp(array('node', 'php', 'filter_test'));
+
+ // Create Basic page node type.
+ $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
+
+ // Create Filtered HTML format.
+ $filtered_html_format = array(
+ 'format' => 'filtered_html',
+ 'name' => 'Filtered HTML',
+ );
+ $filtered_html_format = (object) $filtered_html_format;
+ filter_format_save($filtered_html_format);
+
+ $filtered_html_permission = filter_permission_name($filtered_html_format);
+ user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array($filtered_html_permission));
+
$this->admin_user = $this->drupalCreateUser(array('administer modules', 'administer filters', 'administer site configuration'));
$this->drupalLogin($this->admin_user);
}
@@ -750,8 +769,8 @@ class FilterSecurityTestCase extends DrupalWebTestCase {
function testDisableFilterModule() {
// Create a new node.
$node = $this->drupalCreateNode(array('promote' => 1));
- $body_raw = $node->body[LANGUAGE_NONE][0]['value'];
- $format_id = $node->body[LANGUAGE_NONE][0]['format'];
+ $body_raw = $node->body[LANGUAGE_NOT_SPECIFIED][0]['value'];
+ $format_id = $node->body[LANGUAGE_NOT_SPECIFIED][0]['format'];
$this->drupalGet('node/' . $node->nid);
$this->assertText($body_raw, t('Node body found.'));
@@ -1823,3 +1842,62 @@ class FilterHooksTestCase extends DrupalWebTestCase {
}
}
+/**
+ * Tests filter settings.
+ */
+class FilterSettingsTestCase extends DrupalWebTestCase {
+ protected $profile = 'testing';
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Filter settings',
+ 'description' => 'Tests filter settings.',
+ 'group' => 'Filter',
+ );
+ }
+
+ /**
+ * Tests explicit and implicit default settings for filters.
+ */
+ function testFilterDefaults() {
+ $filter_info = filter_filter_info();
+ $filters = array_fill_keys(array_keys($filter_info), array());
+
+ // Create text format using filter default settings.
+ $filter_defaults_format = (object) array(
+ 'format' => 'filter_defaults',
+ 'name' => 'Filter defaults',
+ 'filters' => $filters,
+ );
+ filter_format_save($filter_defaults_format);
+
+ // Verify that default weights defined in hook_filter_info() were applied.
+ $saved_settings = array();
+ foreach ($filter_defaults_format->filters as $name => $settings) {
+ $expected_weight = (isset($filter_info[$name]['weight']) ? $filter_info[$name]['weight'] : 0);
+ $this->assertEqual($settings['weight'], $expected_weight, format_string('@name filter weight %saved equals %default', array(
+ '@name' => $name,
+ '%saved' => $settings['weight'],
+ '%default' => $expected_weight,
+ )));
+ $saved_settings[$name]['weight'] = $expected_weight;
+ }
+
+ // Re-save the text format.
+ filter_format_save($filter_defaults_format);
+ // Reload it from scratch.
+ filter_formats_reset();
+ $filter_defaults_format = filter_format_load($filter_defaults_format->format);
+ $filter_defaults_format->filters = filter_list_format($filter_defaults_format->format);
+
+ // Verify that saved filter settings have not been changed.
+ foreach ($filter_defaults_format->filters as $name => $settings) {
+ $this->assertEqual($settings->weight, $saved_settings[$name]['weight'], format_string('@name filter weight %saved equals %previous', array(
+ '@name' => $name,
+ '%saved' => $settings->weight,
+ '%previous' => $saved_settings[$name]['weight'],
+ )));
+ }
+ }
+}
+
diff --git a/core/modules/forum/forum.install b/core/modules/forum/forum.install
index 2eebd7f..946f9c4 100644
--- a/core/modules/forum/forum.install
+++ b/core/modules/forum/forum.install
@@ -33,6 +33,7 @@ function forum_enable() {
$edit = array(
'name' => t('Forums'),
'machine_name' => 'forums',
+ 'langcode' => language_default()->langcode,
'description' => t('Forum navigation vocabulary'),
'hierarchy' => 1,
'module' => 'forum',
@@ -62,6 +63,7 @@ function forum_enable() {
// Create a default forum so forum posts can be created.
$edit = array(
'name' => t('General discussion'),
+ 'langcode' => language_default()->langcode,
'description' => '',
'parent' => array(0),
'vid' => $vocabulary->vid,
diff --git a/core/modules/forum/forum.test b/core/modules/forum/forum.test
index 663b872..b5b8ae4 100644
--- a/core/modules/forum/forum.test
+++ b/core/modules/forum/forum.test
@@ -27,7 +27,7 @@ class ForumTestCase extends DrupalWebTestCase {
* Enable modules and create users with specific permissions.
*/
function setUp() {
- parent::setUp('taxonomy', 'comment', 'forum');
+ parent::setUp(array('taxonomy', 'comment', 'forum', 'node', 'block', 'menu', 'help'));
// Create users.
$this->admin_user = $this->drupalCreateUser(array(
'access administration pages',
@@ -49,7 +49,7 @@ class ForumTestCase extends DrupalWebTestCase {
'edit own forum content',
'delete own forum content',
));
- $this->web_user = $this->drupalCreateUser(array());
+ $this->web_user = $this->drupalCreateUser();
}
/**
@@ -147,7 +147,7 @@ class ForumTestCase extends DrupalWebTestCase {
$this->assertFieldByXPath($xpath, '6', t('Number of posts found.'));
// Test loading multiple forum nodes on the front page.
- $this->drupalLogin($this->drupalCreateUser(array('administer content types', 'create forum content')));
+ $this->drupalLogin($this->drupalCreateUser(array('administer content types', 'create forum content', 'post comments')));
$this->drupalPost('admin/structure/types/manage/forum', array('node_options[promote]' => 'promote'), t('Save content type'));
$this->createForumTopic($this->forum, FALSE);
$this->createForumTopic($this->forum, FALSE);
@@ -156,7 +156,7 @@ class ForumTestCase extends DrupalWebTestCase {
// Test adding a comment to a forum topic.
$node = $this->createForumTopic($this->forum, FALSE);
$edit = array();
- $edit['comment_body[' . LANGUAGE_NONE . '][0][value]'] = $this->randomName();
+ $edit['comment_body[' . LANGUAGE_NOT_SPECIFIED . '][0][value]'] = $this->randomName();
$this->drupalPost("node/$node->nid", $edit, t('Save'));
$this->assertResponse(200);
@@ -180,7 +180,7 @@ class ForumTestCase extends DrupalWebTestCase {
// Create an orphan forum item.
$this->drupalLogin($this->admin_user);
- $this->drupalPost('node/add/forum', array('title' => $this->randomName(10), 'body[' . LANGUAGE_NONE .'][0][value]' => $this->randomName(120)), t('Save'));
+ $this->drupalPost('node/add/forum', array('title' => $this->randomName(10), 'body[' . LANGUAGE_NOT_SPECIFIED .'][0][value]' => $this->randomName(120)), t('Save'));
$nid_count = db_query('SELECT COUNT(nid) FROM {node}')->fetchField();
$this->assertEqual(0, $nid_count, t('A forum node was not created when missing a forum vocabulary.'));
@@ -383,7 +383,7 @@ class ForumTestCase extends DrupalWebTestCase {
$title = $this->randomName(20);
$body = $this->randomName(200);
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$edit = array(
"title" => $title,
"body[$langcode][0][value]" => $body,
@@ -407,7 +407,7 @@ class ForumTestCase extends DrupalWebTestCase {
// Retrieve node object, ensure that the topic was created and in the proper forum.
$node = $this->drupalGetNodeByTitle($title);
$this->assertTrue($node != NULL, t('Node @title was loaded', array('@title' => $title)));
- $this->assertEqual($node->taxonomy_forums[LANGUAGE_NONE][0]['tid'], $tid, 'Saved forum topic was in the expected forum');
+ $this->assertEqual($node->taxonomy_forums[LANGUAGE_NOT_SPECIFIED][0]['tid'], $tid, 'Saved forum topic was in the expected forum');
// View forum topic.
$this->drupalGet('node/' . $node->nid);
@@ -474,7 +474,7 @@ class ForumTestCase extends DrupalWebTestCase {
if ($response == 200) {
// Edit forum node (including moving it to another forum).
$edit = array();
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$edit["title"] = 'node/' . $node->nid;
$edit["body[$langcode][0][value]"] = $this->randomName(256);
// Assume the topic is initially associated with $forum.
diff --git a/core/modules/help/help.test b/core/modules/help/help.test
index a37afb2..3e62926 100644
--- a/core/modules/help/help.test
+++ b/core/modules/help/help.test
@@ -9,6 +9,9 @@
* Tests help display and user access for all modules implementing help.
*/
class HelpTestCase extends DrupalWebTestCase {
+ // Tests help implementations of many arbitrary core modules.
+ protected $profile = 'standard';
+
/**
* The admin user that will be created.
*/
diff --git a/core/modules/image/config/image.styles.large.xml b/core/modules/image/config/image.styles.large.xml
new file mode 100644
index 0000000..62448c1
--- /dev/null
+++ b/core/modules/image/config/image.styles.large.xml
@@ -0,0 +1,16 @@
+
+
+ large
+
+
+ image_scale
+ image_scale_480_480_1
+
+ 480
+ 480
+ 1
+
+ 0
+
+
+
diff --git a/core/modules/image/config/image.styles.medium.xml b/core/modules/image/config/image.styles.medium.xml
new file mode 100644
index 0000000..d301877
--- /dev/null
+++ b/core/modules/image/config/image.styles.medium.xml
@@ -0,0 +1,16 @@
+
+
+ medium
+
+
+ image_scale
+ image_scale_220_220_1
+
+ 220
+ 220
+ 1
+
+ 0
+
+
+
diff --git a/core/modules/image/config/image.styles.thumbnail.xml b/core/modules/image/config/image.styles.thumbnail.xml
new file mode 100644
index 0000000..385abe6
--- /dev/null
+++ b/core/modules/image/config/image.styles.thumbnail.xml
@@ -0,0 +1,16 @@
+
+
+ thumbnail
+
+
+ image_scale
+ image_scale_100_100_1
+
+ 100
+ 100
+ 1
+
+ 0
+
+
+
diff --git a/core/modules/image/image.admin.inc b/core/modules/image/image.admin.inc
index 9643841..539e756 100644
--- a/core/modules/image/image.admin.inc
+++ b/core/modules/image/image.admin.inc
@@ -38,13 +38,6 @@ function image_style_form($form, &$form_state, $style) {
$title = t('Edit %name style', array('%name' => $style['name']));
drupal_set_title($title, PASS_THROUGH);
- // Adjust this form for styles that must be overridden to edit.
- $editable = (bool) ($style['storage'] & IMAGE_STORAGE_EDITABLE);
-
- if (!$editable && empty($form_state['input'])) {
- drupal_set_message(t('This image style is currently being provided by a module. Click the "Override defaults" button to change its settings.'), 'warning');
- }
-
$form_state['image_style'] = $style;
$form['#tree'] = TRUE;
$form['#attached']['css'][drupal_get_path('module', 'image') . '/image.admin.css'] = array();
@@ -56,27 +49,15 @@ function image_style_form($form, &$form_state, $style) {
'#markup' => theme('image_style_preview', array('style' => $style)),
);
- // Allow the name of the style to be changed, unless this style is
- // provided by a module's hook_default_image_styles().
- if ($style['storage'] & IMAGE_STORAGE_MODULE) {
- $form['name'] = array(
- '#type' => 'item',
- '#title' => t('Image style name'),
- '#markup' => $style['name'],
- '#description' => t('This image style is being provided by %module module and may not be renamed.', array('%module' => $style['module'])),
- );
- }
- else {
- $form['name'] = array(
- '#type' => 'textfield',
- '#size' => '64',
- '#title' => t('Image style name'),
- '#default_value' => $style['name'],
- '#description' => t('The name is used in URLs for generated images. Use only lowercase alphanumeric characters, underscores (_), and hyphens (-).'),
- '#element_validate' => array('image_style_name_validate'),
- '#required' => TRUE,
- );
- }
+ $form['name'] = array(
+ '#type' => 'textfield',
+ '#size' => '64',
+ '#title' => t('Image style name'),
+ '#default_value' => $style['name'],
+ '#description' => t('The name is used in URLs for generated images. Use only lowercase alphanumeric characters, underscores (_), and hyphens (-).'),
+ '#element_validate' => array('image_style_name_validate'),
+ '#required' => TRUE,
+ );
// Build the list of existing image effects for this image style.
$form['effects'] = array(
@@ -95,25 +76,19 @@ function image_style_form($form, &$form_state, $style) {
'#title' => t('Weight for @title', array('@title' => $effect['label'])),
'#title_display' => 'invisible',
'#default_value' => $effect['weight'],
- '#access' => $editable,
);
- // Only attempt to display these fields for editable styles as the 'ieid'
- // key is not set for styles defined in code.
- if ($editable) {
- $form['effects'][$key]['configure'] = array(
- '#type' => 'link',
- '#title' => t('edit'),
- '#href' => 'admin/config/media/image-styles/edit/' . $style['name'] . '/effects/' . $effect['ieid'],
- '#access' => $editable && isset($effect['form callback']),
- );
- $form['effects'][$key]['remove'] = array(
- '#type' => 'link',
- '#title' => t('delete'),
- '#href' => 'admin/config/media/image-styles/edit/' . $style['name'] . '/effects/' . $effect['ieid'] . '/delete',
- '#access' => $editable,
- );
- }
+ $form['effects'][$key]['configure'] = array(
+ '#type' => 'link',
+ '#title' => t('edit'),
+ '#href' => 'admin/config/media/image-styles/edit/' . $style['name'] . '/effects/' . $key,
+ '#access' => isset($effect['form callback']),
+ );
+ $form['effects'][$key]['remove'] = array(
+ '#type' => 'link',
+ '#title' => t('delete'),
+ '#href' => 'admin/config/media/image-styles/edit/' . $style['name'] . '/effects/' . $key . '/delete',
+ );
}
// Build the new image effect addition form and add it to the effect list.
@@ -124,7 +99,6 @@ function image_style_form($form, &$form_state, $style) {
$form['effects']['new'] = array(
'#tree' => FALSE,
'#weight' => isset($form_state['input']['weight']) ? $form_state['input']['weight'] : NULL,
- '#access' => $editable,
);
$form['effects']['new']['new'] = array(
'#type' => 'select',
@@ -148,17 +122,9 @@ function image_style_form($form, &$form_state, $style) {
// Show the Override or Submit button for this style.
$form['actions'] = array('#type' => 'actions');
- $form['actions']['override'] = array(
- '#type' => 'submit',
- '#value' => t('Override defaults'),
- '#validate' => array(),
- '#submit' => array('image_style_form_override_submit'),
- '#access' => !$editable,
- );
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Update style'),
- '#access' => $editable,
);
return $form;
@@ -188,43 +154,54 @@ function image_style_form_add_submit($form, &$form_state) {
}
// If there's no form, immediately add the image effect.
else {
- $effect['isid'] = $style['isid'];
- $effect['weight'] = $form_state['values']['weight'];
- image_effect_save($effect);
+ $effect = array(
+ 'name' => $effect['name'],
+ 'data' => array(),
+ 'weight' => $form_state['values']['weight'],
+ );
+ image_effect_save($style['name'], $effect);
drupal_set_message(t('The image effect was successfully applied.'));
}
}
/**
- * Submit handler for overriding a module-defined style.
- */
-function image_style_form_override_submit($form, &$form_state) {
- drupal_set_message(t('The %style style has been overridden, allowing you to change its settings.', array('%style' => $form_state['image_style']['name'])));
- image_default_style_save($form_state['image_style']);
-}
-
-/**
* Submit handler for saving an image style.
*/
function image_style_form_submit($form, &$form_state) {
- // Update the image style name if it has changed.
$style = $form_state['image_style'];
- if (isset($form_state['values']['name']) && $style['name'] != $form_state['values']['name']) {
- $style['name'] = $form_state['values']['name'];
- }
// Update image effect weights.
if (!empty($form_state['values']['effects'])) {
foreach ($form_state['values']['effects'] as $ieid => $effect_data) {
if (isset($style['effects'][$ieid])) {
- $effect = $style['effects'][$ieid];
- $effect['weight'] = $effect_data['weight'];
- image_effect_save($effect);
+ $effect = array(
+ 'name' => $style['effects'][$ieid]['name'],
+ 'data' => $style['effects'][$ieid]['data'],
+ 'weight' => $effect_data['weight'],
+ 'ieid' => $ieid,
+ );
+ $style['effects'][$ieid] = $effect;
}
}
}
+ // Update the image style name if it has changed. We also need to delete the
+ // old style, because there is no concept of rename at the moment, just
+ // create and delete.
+ // @todo The config API does not yet support the concept of a rename, but
+ // hooks need to be able to change old style name references to the new
+ // name, so first save the new style, then delete the old, so that the
+ // delete function can receive the name of a fully saved style to update
+ // references to.
+ if (isset($form_state['values']['name']) && $style['name'] != $form_state['values']['name']) {
+ $old_style = $style;
+ $style['name'] = $form_state['values']['name'];
+ }
image_style_save($style);
+ if (isset($old_style)) {
+ image_style_delete($old_style, $style['name']);
+ }
+
if ($form_state['values']['op'] == t('Update style')) {
drupal_set_message(t('Changes to the style have been saved.'));
}
@@ -273,7 +250,7 @@ function image_style_add_form_submit($form, &$form_state) {
function image_style_name_validate($element, $form_state) {
// Check for duplicates.
$styles = image_styles();
- if (isset($styles[$element['#value']]) && (!isset($form_state['image_style']['isid']) || $styles[$element['#value']]['isid'] != $form_state['image_style']['isid'])) {
+ if (isset($styles[$element['#value']]) && (!isset($form_state['image_style']['name']) || $styles[$element['#value']]['name'] != $form_state['image_style']['name'])) {
form_set_error($element['#name'], t('The image style name %name is already in use.', array('%name' => $element['#value'])));
}
@@ -324,30 +301,6 @@ function image_style_delete_form_submit($form, &$form_state) {
}
/**
- * Confirmation form to revert a database style to its default.
- */
-function image_style_revert_form($form, $form_state, $style) {
- $form_state['image_style'] = $style;
-
- return confirm_form(
- $form,
- t('Revert the %style style?', array('%style' => $style['name'])),
- 'admin/config/media/image-styles',
- t('Reverting this style will delete the customized settings and restore the defaults provided by the @module module.', array('@module' => $style['module'])),
- t('Revert'), t('Cancel')
- );
-}
-
-/**
- * Submit handler to convert an overridden style to its default.
- */
-function image_style_revert_form_submit($form, &$form_state) {
- drupal_set_message(t('The %style style has been reverted to its defaults.', array('%style' => $form_state['image_style']['name'])));
- image_default_style_revert($form_state['image_style']);
- $form_state['redirect'] = 'admin/config/media/image-styles';
-}
-
-/**
* Form builder; Form for adding and editing image effects.
*
* This form is used universally for editing all image effects. Each effect adds
@@ -416,12 +369,14 @@ function image_effect_form($form, &$form_state, $style, $effect) {
* Submit handler for updating an image effect.
*/
function image_effect_form_submit($form, &$form_state) {
- $style = $form_state['image_style'];
- $effect = array_merge($form_state['image_effect'], $form_state['values']);
- $effect['isid'] = $style['isid'];
- image_effect_save($effect);
+ $effect = array(
+ 'name' => $form_state['image_effect']['name'],
+ 'data' => $form_state['values']['data'],
+ 'weight' => $form_state['values']['weight'],
+ );
+ image_effect_save($form_state['image_style']['name'], $effect);
drupal_set_message(t('The image effect was successfully applied.'));
- $form_state['redirect'] = 'admin/config/media/image-styles/edit/' . $style['name'];
+ $form_state['redirect'] = 'admin/config/media/image-styles/edit/' . $form_state['image_style']['name'];
}
/**
@@ -449,7 +404,7 @@ function image_effect_delete_form_submit($form, &$form_state) {
$style = $form_state['image_style'];
$effect = $form_state['image_effect'];
- image_effect_delete($effect);
+ image_effect_delete($style['name'], $effect);
drupal_set_message(t('The image effect %name has been deleted.', array('%name' => $effect['label'])));
$form_state['redirect'] = 'admin/config/media/image-styles/edit/' . $style['name'];
}
@@ -645,31 +600,19 @@ function image_rotate_form($data) {
function theme_image_style_list($variables) {
$styles = $variables['styles'];
- $header = array(t('Style name'), t('Settings'), array('data' => t('Operations'), 'colspan' => 3));
+ $header = array(t('Style name'), array('data' => t('Operations'), 'colspan' => 3));
$rows = array();
+ $link_attributes = array(
+ 'attributes' => array(
+ 'class' => array('image-style-link'),
+ ),
+ );
+
foreach ($styles as $style) {
$row = array();
$row[] = l($style['name'], 'admin/config/media/image-styles/edit/' . $style['name']);
- $link_attributes = array(
- 'attributes' => array(
- 'class' => array('image-style-link'),
- ),
- );
- if ($style['storage'] == IMAGE_STORAGE_NORMAL) {
- $row[] = t('Custom');
- $row[] = l(t('edit'), 'admin/config/media/image-styles/edit/' . $style['name'], $link_attributes);
- $row[] = l(t('delete'), 'admin/config/media/image-styles/delete/' . $style['name'], $link_attributes);
- }
- elseif ($style['storage'] == IMAGE_STORAGE_OVERRIDE) {
- $row[] = t('Overridden');
- $row[] = l(t('edit'), 'admin/config/media/image-styles/edit/' . $style['name'], $link_attributes);
- $row[] = l(t('revert'), 'admin/config/media/image-styles/revert/' . $style['name'], $link_attributes);
- }
- else {
- $row[] = t('Default');
- $row[] = l(t('edit'), 'admin/config/media/image-styles/edit/' . $style['name'], $link_attributes);
- $row[] = '';
- }
+ $row[] = l(t('edit'), 'admin/config/media/image-styles/edit/' . $style['name'], $link_attributes);
+ $row[] = l(t('delete'), 'admin/config/media/image-styles/delete/' . $style['name'], $link_attributes);
$rows[] = $row;
}
@@ -694,13 +637,12 @@ function theme_image_style_list($variables) {
*/
function theme_image_style_effects($variables) {
$form = $variables['form'];
-
$rows = array();
foreach (element_children($form) as $key) {
$row = array();
$form[$key]['weight']['#attributes']['class'] = array('image-effect-order-weight');
- if (is_numeric($key)) {
+ if ($key != 'new') {
$summary = drupal_render($form[$key]['summary']);
$row[] = drupal_render($form[$key]['label']) . (empty($summary) ? '' : ' ' . $summary);
$row[] = drupal_render($form[$key]['weight']);
@@ -728,7 +670,7 @@ function theme_image_style_effects($variables) {
array('data' => t('Operations'), 'colspan' => 2),
);
- if (count($rows) == 1 && $form['new']['#access']) {
+ if (count($rows) == 1 && (!isset($form['new']['#access']) || $form['new']['#access'])) {
array_unshift($rows, array(array(
'data' => t('There are currently no effects in this style. Add one by selecting an option below.'),
'colspan' => 4,
diff --git a/core/modules/image/image.install b/core/modules/image/image.install
index 02be57c..91349a9 100644
--- a/core/modules/image/image.install
+++ b/core/modules/image/image.install
@@ -23,87 +23,6 @@ function image_uninstall() {
}
/**
- * Implements hook_schema().
- */
-function image_schema() {
- $schema = array();
-
- $schema['image_styles'] = array(
- 'description' => 'Stores configuration options for image styles.',
- 'fields' => array(
- 'isid' => array(
- 'description' => 'The primary identifier for an image style.',
- 'type' => 'serial',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- ),
- 'name' => array(
- 'description' => 'The style name.',
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE,
- ),
- ),
- 'primary key' => array('isid'),
- 'unique keys' => array(
- 'name' => array('name'),
- ),
- );
-
- $schema['image_effects'] = array(
- 'description' => 'Stores configuration options for image effects.',
- 'fields' => array(
- 'ieid' => array(
- 'description' => 'The primary identifier for an image effect.',
- 'type' => 'serial',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- ),
- 'isid' => array(
- 'description' => 'The {image_styles}.isid for an image style.',
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- ),
- 'weight' => array(
- 'description' => 'The weight of the effect in the style.',
- 'type' => 'int',
- 'unsigned' => FALSE,
- 'not null' => TRUE,
- 'default' => 0,
- ),
- 'name' => array(
- 'description' => 'The unique name of the effect to be executed.',
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE,
- ),
- 'data' => array(
- 'description' => 'The configuration data for the effect.',
- 'type' => 'blob',
- 'not null' => TRUE,
- 'size' => 'big',
- 'serialize' => TRUE,
- ),
- ),
- 'primary key' => array('ieid'),
- 'indexes' => array(
- 'isid' => array('isid'),
- 'weight' => array('weight'),
- ),
- 'foreign keys' => array(
- 'image_style' => array(
- 'table' => 'image_styles',
- 'columns' => array('isid' => 'isid'),
- ),
- ),
- );
-
- return $schema;
-}
-
-/**
* Implements hook_field_schema().
*/
function image_field_schema($field) {
diff --git a/core/modules/image/image.module b/core/modules/image/image.module
index 0e48d15..bcccbf7 100644
--- a/core/modules/image/image.module
+++ b/core/modules/image/image.module
@@ -135,15 +135,6 @@ function image_menu() {
'access arguments' => array('administer image styles'),
'file' => 'image.admin.inc',
);
- $items['admin/config/media/image-styles/revert/%image_style'] = array(
- 'title' => 'Revert style',
- 'description' => 'Revert an image style.',
- 'load arguments' => array(NULL, (string) IMAGE_STORAGE_OVERRIDE),
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('image_style_revert_form', 5),
- 'access arguments' => array('administer image styles'),
- 'file' => 'image.admin.inc',
- );
$items['admin/config/media/image-styles/edit/%image_style/effects/%image_effect'] = array(
'title' => 'Edit image effect',
'description' => 'Edit an existing effect within a style.',
@@ -331,45 +322,6 @@ function image_file_predelete($file) {
}
/**
- * Implements hook_image_default_styles().
- */
-function image_image_default_styles() {
- $styles = array();
-
- $styles['thumbnail'] = array(
- 'effects' => array(
- array(
- 'name' => 'image_scale',
- 'data' => array('width' => 100, 'height' => 100, 'upscale' => 1),
- 'weight' => 0,
- ),
- )
- );
-
- $styles['medium'] = array(
- 'effects' => array(
- array(
- 'name' => 'image_scale',
- 'data' => array('width' => 220, 'height' => 220, 'upscale' => 1),
- 'weight' => 0,
- ),
- )
- );
-
- $styles['large'] = array(
- 'effects' => array(
- array(
- 'name' => 'image_scale',
- 'data' => array('width' => 480, 'height' => 480, 'upscale' => 0),
- 'weight' => 0,
- ),
- )
- );
-
- return $styles;
-}
-
-/**
* Implements hook_image_style_save().
*/
function image_image_style_save($style) {
@@ -483,55 +435,30 @@ function image_path_flush($path) {
* @see image_style_load()
*/
function image_styles() {
- $styles = &drupal_static(__FUNCTION__);
-
- // Grab from cache or build the array.
- if (!isset($styles)) {
- if ($cache = cache()->get('image_styles')) {
- $styles = $cache->data;
- }
- else {
+ // @todo Configuration must not be statically cached nor cache-system cached.
+ // However, there's a drupal_alter() involved here.
+
+// $styles = &drupal_static(__FUNCTION__);
+//
+// // Grab from cache or build the array.
+// if (!isset($styles)) {
+// if ($cache = cache()->get('image_styles')) {
+// $styles = $cache->data;
+// }
+// else {
$styles = array();
- // Select the module-defined styles.
- foreach (module_implements('image_default_styles') as $module) {
- $module_styles = module_invoke($module, 'image_default_styles');
- foreach ($module_styles as $style_name => $style) {
- $style['name'] = $style_name;
- $style['module'] = $module;
- $style['storage'] = IMAGE_STORAGE_DEFAULT;
- foreach ($style['effects'] as $key => $effect) {
- $definition = image_effect_definition_load($effect['name']);
- $effect = array_merge($definition, $effect);
- $style['effects'][$key] = $effect;
- }
- $styles[$style_name] = $style;
- }
- }
-
- // Select all the user-defined styles.
- $user_styles = db_select('image_styles', NULL, array('fetch' => PDO::FETCH_ASSOC))
- ->fields('image_styles')
- ->orderBy('name')
- ->execute()
- ->fetchAllAssoc('name', PDO::FETCH_ASSOC);
-
- // Allow the user styles to override the module styles.
- foreach ($user_styles as $style_name => $style) {
- $style['module'] = NULL;
- $style['storage'] = IMAGE_STORAGE_NORMAL;
- $style['effects'] = image_style_effects($style);
- if (isset($styles[$style_name]['module'])) {
- $style['module'] = $styles[$style_name]['module'];
- $style['storage'] = IMAGE_STORAGE_OVERRIDE;
- }
- $styles[$style_name] = $style;
+ // Select the styles we have configured.
+ $configured_styles = config_get_verified_storage_names_with_prefix('image.styles');
+ foreach ($configured_styles as $config_name) {
+ // @todo Allow to retrieve the name without prefix only.
+ $style = image_style_load(str_replace('image.styles.', '', $config_name));
+ $styles[$style['name']] = $style;
}
-
drupal_alter('image_styles', $styles);
- cache()->set('image_styles', $styles);
- }
- }
+// cache()->set('image_styles', $styles);
+// }
+// }
return $styles;
}
@@ -541,45 +468,31 @@ function image_styles() {
*
* @param $name
* The name of the style.
- * @param $isid
- * Optional. The numeric id of a style if the name is not known.
- * @param $include
- * If set, this loader will restrict to a specific type of image style, may be
- * one of the defined Image style storage constants.
* @return
* An image style array containing the following keys:
- * - "isid": The unique image style ID.
* - "name": The unique image style name.
* - "effects": An array of image effects within this image style.
- * If the image style name or ID is not valid, an empty array is returned.
+ * If the image style name is not valid, an empty array is returned.
* @see image_effect_load()
*/
-function image_style_load($name = NULL, $isid = NULL, $include = NULL) {
- $styles = image_styles();
-
- // If retrieving by name.
- if (isset($name) && isset($styles[$name])) {
- $style = $styles[$name];
- }
+function image_style_load($name) {
+ $style = config('image.styles.' . $name)->get();
- // If retrieving by image style id.
- if (!isset($name) && isset($isid)) {
- foreach ($styles as $name => $database_style) {
- if (isset($database_style['isid']) && $database_style['isid'] == $isid) {
- $style = $database_style;
- break;
- }
- }
+ // @todo Requires a more reliable + generic method to check for whether the
+ // configuration object exists.
+ if (!isset($style['name'])) {
+ return FALSE;
}
- // Restrict to the specific type of flag. This bitwise operation basically
- // states "if the storage is X, then allow".
- if (isset($style) && (!isset($include) || ($style['storage'] & (int) $include))) {
- return $style;
+ foreach ($style['effects'] as $ieid => $effect) {
+ $definition = image_effect_definition_load($effect['name']);
+ $effect = array_merge($definition, $effect);
+ $style['effects'][$ieid] = $effect;
}
+ // Sort effects by weight.
+ uasort($style['effects'], 'drupal_sort_weight');
- // Otherwise the style was not found.
- return FALSE;
+ return $style;
}
/**
@@ -588,22 +501,21 @@ function image_style_load($name = NULL, $isid = NULL, $include = NULL) {
* @param style
* An image style array.
* @return
- * An image style array. In the case of a new style, 'isid' will be populated.
+ * An image style array.
*/
function image_style_save($style) {
- if (isset($style['isid']) && is_numeric($style['isid'])) {
- // Load the existing style to make sure we account for renamed styles.
- $old_style = image_style_load(NULL, $style['isid']);
- image_style_flush($old_style);
- drupal_write_record('image_styles', $style, 'isid');
- if ($old_style['name'] != $style['name']) {
- $style['old_name'] = $old_style['name'];
- }
+ $config = config('image.styles.' . $style['name']);
+ $config->set('name', $style['name']);
+ if (isset($style['effects'])) {
+ $config->set('effects', $style['effects']);
}
else {
- drupal_write_record('image_styles', $style);
- $style['is_new'] = TRUE;
+ $config->set('effects', array());
}
+ $config->save();
+ // @todo is_new must only be set when the configuration object did not exist
+ // yet.
+ $style['is_new'] = TRUE;
// Let other modules update as necessary on save.
module_invoke_all('image_style_save', $style);
@@ -628,8 +540,8 @@ function image_style_save($style) {
function image_style_delete($style, $replacement_style_name = '') {
image_style_flush($style);
- db_delete('image_effects')->condition('isid', $style['isid'])->execute();
- db_delete('image_styles')->condition('isid', $style['isid'])->execute();
+ $config = config('image.styles.' . $style['name']);
+ $config->delete();
// Let other modules update as necessary on save.
$style['old_name'] = $style['name'];
@@ -648,17 +560,11 @@ function image_style_delete($style, $replacement_style_name = '') {
* An array of image effects associated with specified image style in the
* format array('isid' => array()), or an empty array if the specified style
* has no effects.
+ *
+ * @todo Remove this function; it's entirely obsolete.
*/
function image_style_effects($style) {
- $effects = image_effects();
- $style_effects = array();
- foreach ($effects as $effect) {
- if ($style['isid'] == $effect['isid']) {
- $style_effects[$effect['ieid']] = $effect;
- }
- }
-
- return $style_effects;
+ return $style['effects'];
}
/**
@@ -854,11 +760,11 @@ function image_style_flush($style) {
// Let other modules update as necessary on flush.
module_invoke_all('image_style_flush', $style);
- // Clear image style and effect caches.
- cache()->delete('image_styles');
- cache()->deletePrefix('image_effects:');
- drupal_static_reset('image_styles');
- drupal_static_reset('image_effects');
+// // Clear image style and effect caches.
+// cache()->delete('image_styles');
+// cache()->deletePrefix('image_effects:');
+// drupal_static_reset('image_styles');
+// drupal_static_reset('image_effects');
// Clear field caches so that formatters may be added for this style.
field_info_cache_clear();
@@ -876,15 +782,15 @@ function image_style_flush($style) {
*
* @param $style_name
* The name of the style to be used with this image.
- * @param $uri
+ * @param $path
* The path to the image.
* @return
* The absolute URL where a style image can be downloaded, suitable for use
* in an
tag. Requesting the URL will cause the image to be created.
* @see image_style_deliver()
*/
-function image_style_url($style_name, $uri) {
- $uri = image_style_path($style_name, $uri);
+function image_style_url($style_name, $path) {
+ $uri = image_style_path($style_name, $path);
// If not using clean URLs, the image derivative callback is only available
// with the query string. If the file does not exist, use url() to ensure
@@ -925,44 +831,6 @@ function image_style_path($style_name, $uri) {
}
/**
- * Save a default image style to the database.
- *
- * @param style
- * An image style array provided by a module.
- * @return
- * An image style array. The returned style array will include the new 'isid'
- * assigned to the style.
- */
-function image_default_style_save($style) {
- $style = image_style_save($style);
- $effects = array();
- foreach ($style['effects'] as $effect) {
- $effect['isid'] = $style['isid'];
- $effect = image_effect_save($effect);
- $effects[$effect['ieid']] = $effect;
- }
- $style['effects'] = $effects;
- return $style;
-}
-
-/**
- * Revert the changes made by users to a default image style.
- *
- * @param style
- * An image style array.
- * @return
- * Boolean TRUE if the operation succeeded.
- */
-function image_default_style_revert($style) {
- image_style_flush($style);
-
- db_delete('image_effects')->condition('isid', $style['isid'])->execute();
- db_delete('image_styles')->condition('isid', $style['isid'])->execute();
-
- return TRUE;
-}
-
-/**
* Pull in image effects exposed by modules implementing hook_image_effect_info().
*
* @return
@@ -1015,8 +883,6 @@ function image_effect_definitions() {
*
* @param $effect
* The name of the effect definition to load.
- * @param $style
- * An image style array to which this effect will be added.
* @return
* An array containing the image effect definition with the following keys:
* - "effect": The unique name for the effect being performed. Usually prefixed
@@ -1028,18 +894,8 @@ function image_effect_definitions() {
* - "summary": (optional) The name of a theme function that will display a
* one-line summary of the effect. Does not include the "theme_" prefix.
*/
-function image_effect_definition_load($effect, $style_name = NULL) {
+function image_effect_definition_load($effect) {
$definitions = image_effect_definitions();
-
- // If a style is specified, do not allow loading of default style
- // effects.
- if (isset($style_name)) {
- $style = image_style_load($style_name, NULL);
- if ($style['storage'] == IMAGE_STORAGE_DEFAULT) {
- return FALSE;
- }
- }
-
return isset($definitions[$effect]) ? $definitions[$effect] : FALSE;
}
@@ -1049,6 +905,8 @@ function image_effect_definition_load($effect, $style_name = NULL) {
* @return
* An array of all image effects.
* @see image_effect_load()
+ *
+ * @todo Remove after moving/resolving the todo.
*/
function image_effects() {
$effects = &drupal_static(__FUNCTION__);
@@ -1057,6 +915,9 @@ function image_effects() {
$effects = array();
// Add database image effects.
+ // @todo Strictly speaking, this is obsolete. However, it demonstrates a
+ // use-case for retrieving/listing configuration objects using a wildcard
+ // within the name (instead of only the suffix).
$result = db_select('image_effects', NULL, array('fetch' => PDO::FETCH_ASSOC))
->fields('image_effects')
->orderBy('image_effects.weight', 'ASC')
@@ -1082,13 +943,10 @@ function image_effects() {
* The image effect ID.
* @param $style_name
* The image style name.
- * @param $include
- * If set, this loader will restrict to a specific type of image style, may be
- * one of the defined Image style storage constants.
+ *
* @return
* An image effect array, consisting of the following keys:
* - "ieid": The unique image effect ID.
- * - "isid": The unique image style ID that contains this image effect.
* - "weight": The weight of this image effect within the image style.
* - "name": The name of the effect definition that powers this image effect.
* - "data": An array of configuration options for this image effect.
@@ -1098,9 +956,20 @@ function image_effects() {
* @see image_style_load()
* @see image_effect_definition_load()
*/
-function image_effect_load($ieid, $style_name, $include = NULL) {
- if (($style = image_style_load($style_name, NULL, $include)) && isset($style['effects'][$ieid])) {
- return $style['effects'][$ieid];
+function image_effect_load($ieid, $style_name) {
+ if (($style = image_style_load($style_name)) && isset($style['effects'][$ieid])) {
+ $effect = $style['effects'][$ieid];
+ $definition = image_effect_definition_load($effect['name']);
+ $effect = array_merge($definition, $effect);
+ // @todo The effect's key name within the style is unknown. It *should* be
+ // identical to the ieid, but that is in no way guaranteed. And of course,
+ // the ieid key *within* the effect is senseless duplication in the first
+ // place. This problem can be eliminated in many places, but especially
+ // for loaded menu arguments like %image_effect, the actual router
+ // callbacks don't have access to 'ieid' anymore (unless resorting to
+ // dirty %index and %map tricks).
+ $effect['ieid'] = $ieid;
+ return $effect;
}
return FALSE;
}
@@ -1108,19 +977,32 @@ function image_effect_load($ieid, $style_name, $include = NULL) {
/**
* Save an image effect.
*
+ * @param $style_name
+ * The image style this effect belongs to.
* @param $effect
* An image effect array.
* @return
* An image effect array. In the case of a new effect, 'ieid' will be set.
*/
-function image_effect_save($effect) {
- if (!empty($effect['ieid'])) {
- drupal_write_record('image_effects', $effect, 'ieid');
- }
- else {
- drupal_write_record('image_effects', $effect);
+function image_effect_save($style_name, $effect) {
+ $config = config('image.styles.' . $style_name);
+
+ if (!isset($effect['ieid']) || empty($effect['ieid'])) {
+ // We need to generate the ieid and save the new effect.
+ // The machine name is all the elements of the data array concatenated
+ // together, delimited by underscores.
+ $effect['ieid'] = $effect['name'];
+ foreach ($effect['data'] as $key => $value) {
+ $effect['ieid'] .= '_' . $value;
+ }
+ // @todo The machine name must not use any special non-alphanumeric
+ // characters, and may also not contain dots/periods, as that is the
+ // config system's nested key syntax.
+ $effect['ieid'] = preg_replace('@[^a-zA-Z0-9_-]@', '', $effect['ieid']);
}
- $style = image_style_load(NULL, $effect['isid']);
+ $config->set('effects.' . $effect['ieid'], $effect);
+ $config->save();
+ $style = image_style_load($style_name);
image_style_flush($style);
return $effect;
}
@@ -1128,12 +1010,16 @@ function image_effect_save($effect) {
/**
* Delete an image effect.
*
+ * @param $style_name
+ * The image style this effect belongs to.
* @param $effect
* An image effect array.
*/
-function image_effect_delete($effect) {
- db_delete('image_effects')->condition('ieid', $effect['ieid'])->execute();
- $style = image_style_load(NULL, $effect['isid']);
+function image_effect_delete($style_name, $effect) {
+ $config = config('image.styles.' . $style_name);
+ $config->clear('effects.' . $effect['ieid']);
+ $config->save();
+ $style = image_style_load($style_name);
image_style_flush($style);
}
@@ -1161,7 +1047,9 @@ function image_effect_apply($image, $effect) {
* - style_name: The name of the style to be used to alter the original image.
* - uri: The path of the image file relative to the Drupal files directory.
* This function does not work with images outside the files directory nor
- * with remotely hosted images.
+ * with remotely hosted images. This should be in a format such as
+ * 'images/image.jpg', or using a stream wrapper such as
+ * 'public://images/image.jpg'.
* - width: The width of the source image (if known).
* - height: The height of the source image (if known).
* - alt: The alternative text for text-based browsers.
diff --git a/core/modules/image/image.test b/core/modules/image/image.test
index 4d4532c..2c422a7 100644
--- a/core/modules/image/image.test
+++ b/core/modules/image/image.test
@@ -32,7 +32,20 @@ class ImageFieldTestCase extends DrupalWebTestCase {
protected $admin_user;
function setUp() {
- parent::setUp('image');
+ $modules = func_get_args();
+ if (isset($modules[0]) && is_array($modules[0])) {
+ $modules = $modules[0];
+ }
+ $modules[] = 'node';
+ $modules[] = 'image';
+ parent::setUp($modules);
+
+ // Create Basic page and Article node types.
+ if ($this->profile != 'standard') {
+ $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
+ $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
+ }
+
$this->admin_user = $this->drupalCreateUser(array('access content', 'access administration pages', 'administer site configuration', 'administer content types', 'administer nodes', 'create article content', 'edit any article content', 'delete any article content', 'administer image styles'));
$this->drupalLogin($this->admin_user);
}
@@ -92,7 +105,7 @@ class ImageFieldTestCase extends DrupalWebTestCase {
$edit = array(
'title' => $this->randomName(),
);
- $edit['files[' . $field_name . '_' . LANGUAGE_NONE . '_0]'] = drupal_realpath($image->uri);
+ $edit['files[' . $field_name . '_' . LANGUAGE_NOT_SPECIFIED . '_0]'] = drupal_realpath($image->uri);
$this->drupalPost('node/add/' . $type, $edit, t('Save'));
// Retrieve ID of the newly created node from the current URL.
@@ -119,7 +132,7 @@ class ImageStylesPathAndUrlUnitTest extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('image_module_test');
+ parent::setUp(array('image', 'image_module_test'));
$this->style_name = 'style_foo';
image_style_save(array('name' => $this->style_name));
@@ -468,7 +481,7 @@ class ImageAdminStylesUnitTest extends ImageFieldTestCase {
// Load the style by the new name with the new weights.
drupal_static_reset('image_styles');
- $style = image_style_load($style_name, NULL);
+ $style = image_style_load($style_name);
// Confirm the new style order was saved.
$effect_edits_order = array_reverse($effect_edits_order);
@@ -507,76 +520,6 @@ class ImageAdminStylesUnitTest extends ImageFieldTestCase {
}
/**
- * Test to override, edit, then revert a style.
- */
- function testDefaultStyle() {
- // Setup a style to be created and effects to add to it.
- $style_name = 'thumbnail';
- $edit_path = 'admin/config/media/image-styles/edit/' . $style_name;
- $delete_path = 'admin/config/media/image-styles/delete/' . $style_name;
- $revert_path = 'admin/config/media/image-styles/revert/' . $style_name;
-
- // Ensure deleting a default is not possible.
- $this->drupalGet($delete_path);
- $this->assertText(t('Page not found'), t('Default styles may not be deleted.'));
-
- // Ensure that editing a default is not possible (without overriding).
- $this->drupalGet($edit_path);
- $this->assertNoField('edit-name', t('Default styles may not be renamed.'));
- $this->assertNoField('edit-submit', t('Default styles may not be edited.'));
- $this->assertNoField('edit-add', t('Default styles may not have new effects added.'));
-
- // Create an image to make sure the default works before overriding.
- drupal_static_reset('image_styles');
- $style = image_style_load($style_name);
- $image_path = $this->createSampleImage($style);
- $this->assertEqual($this->getImageCount($style), 1, t('Image style %style image %file successfully generated.', array('%style' => $style['name'], '%file' => $image_path)));
-
- // Verify that effects attached to a default style do not have an ieid key.
- foreach ($style['effects'] as $effect) {
- $this->assertFalse(isset($effect['ieid']), t('The %effect effect does not have an ieid.', array('%effect' => $effect['name'])));
- }
-
- // Override the default.
- $this->drupalPost($edit_path, array(), t('Override defaults'));
- $this->assertRaw(t('The %style style has been overridden, allowing you to change its settings.', array('%style' => $style_name)), t('Default image style may be overridden.'));
-
- // Add sample effect to the overridden style.
- $this->drupalPost($edit_path, array('new' => 'image_desaturate'), t('Add'));
- drupal_static_reset('image_styles');
- $style = image_style_load($style_name);
-
- // Verify that effects attached to the style have an ieid now.
- foreach ($style['effects'] as $effect) {
- $this->assertTrue(isset($effect['ieid']), t('The %effect effect has an ieid.', array('%effect' => $effect['name'])));
- }
-
- // The style should now have 2 effect, the original scale provided by core
- // and the desaturate effect we added in the override.
- $effects = array_values($style['effects']);
- $this->assertEqual($effects[0]['name'], 'image_scale', t('The default effect still exists in the overridden style.'));
- $this->assertEqual($effects[1]['name'], 'image_desaturate', t('The added effect exists in the overridden style.'));
-
- // Check that we are unable to rename an overridden style.
- $this->drupalGet($edit_path);
- $this->assertNoField('edit-name', t('Overridden styles may not be renamed.'));
-
- // Create an image to ensure the override works properly.
- $image_path = $this->createSampleImage($style);
- $this->assertEqual($this->getImageCount($style), 1, t('Image style %style image %file successfully generated.', array('%style' => $style['name'], '%file' => $image_path)));
-
- // Revert the image style.
- $this->drupalPost($revert_path, array(), t('Revert'));
- drupal_static_reset('image_styles');
- $style = image_style_load($style_name);
-
- // The style should now have the single effect for scale.
- $effects = array_values($style['effects']);
- $this->assertEqual($effects[0]['name'], 'image_scale', t('The default effect still exists in the reverted style.'));
- $this->assertFalse(array_key_exists(1, $effects), t('The added effect has been removed in the reverted style.'));
- }
-
- /**
* Test deleting a style and choosing a replacement style.
*/
function testStyleReplacement() {
@@ -599,7 +542,7 @@ class ImageAdminStylesUnitTest extends ImageFieldTestCase {
// Test that image is displayed using newly created style.
$this->drupalGet('node/' . $nid);
- $this->assertRaw(image_style_url($style_name, $node->{$field_name}[LANGUAGE_NONE][0]['uri']), t('Image displayed using style @style.', array('@style' => $style_name)));
+ $this->assertRaw(image_style_url($style_name, $node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0]['uri']), t('Image displayed using style @style.', array('@style' => $style_name)));
// Rename the style and make sure the image field is updated.
$new_style_name = strtolower($this->randomName(10));
@@ -609,7 +552,7 @@ class ImageAdminStylesUnitTest extends ImageFieldTestCase {
$this->drupalPost('admin/config/media/image-styles/edit/' . $style_name, $edit, t('Update style'));
$this->assertText(t('Changes to the style have been saved.'), t('Style %name was renamed to %new_name.', array('%name' => $style_name, '%new_name' => $new_style_name)));
$this->drupalGet('node/' . $nid);
- $this->assertRaw(image_style_url($new_style_name, $node->{$field_name}[LANGUAGE_NONE][0]['uri']), t('Image displayed using style replacement style.'));
+ $this->assertRaw(image_style_url($new_style_name, $node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0]['uri']), t('Image displayed using style replacement style.'));
// Delete the style and choose a replacement style.
$edit = array(
@@ -620,7 +563,7 @@ class ImageAdminStylesUnitTest extends ImageFieldTestCase {
$this->assertRaw($message, $message);
$this->drupalGet('node/' . $nid);
- $this->assertRaw(image_style_url('thumbnail', $node->{$field_name}[LANGUAGE_NONE][0]['uri']), t('Image displayed using style replacement style.'));
+ $this->assertRaw(image_style_url('thumbnail', $node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0]['uri']), t('Image displayed using style replacement style.'));
}
}
@@ -636,6 +579,10 @@ class ImageFieldDisplayTestCase extends ImageFieldTestCase {
);
}
+ function setUp() {
+ parent::setUp(array('field_ui'));
+ }
+
/**
* Test image formatters on node display for public files.
*/
@@ -664,7 +611,7 @@ class ImageFieldDisplayTestCase extends ImageFieldTestCase {
$node = node_load($nid, NULL, TRUE);
// Test that the default formatter is being used.
- $image_uri = $node->{$field_name}[LANGUAGE_NONE][0]['uri'];
+ $image_uri = $node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0]['uri'];
$image_info = array(
'uri' => $image_uri,
'width' => 40,
@@ -761,13 +708,13 @@ class ImageFieldDisplayTestCase extends ImageFieldTestCase {
// and title fields do not display until the image has been attached.
$nid = $this->uploadNodeImage($test_image, $field_name, 'article');
$this->drupalGet('node/' . $nid . '/edit');
- $this->assertFieldByName($field_name . '[' . LANGUAGE_NONE . '][0][alt]', '', t('Alt field displayed on article form.'));
- $this->assertFieldByName($field_name . '[' . LANGUAGE_NONE . '][0][title]', '', t('Title field displayed on article form.'));
+ $this->assertFieldByName($field_name . '[' . LANGUAGE_NOT_SPECIFIED . '][0][alt]', '', t('Alt field displayed on article form.'));
+ $this->assertFieldByName($field_name . '[' . LANGUAGE_NOT_SPECIFIED . '][0][title]', '', t('Title field displayed on article form.'));
// Verify that the attached image is being previewed using the 'medium'
// style.
$node = node_load($nid, NULL, TRUE);
$image_info = array(
- 'uri' => image_style_url('medium', $node->{$field_name}[LANGUAGE_NONE][0]['uri']),
+ 'uri' => image_style_url('medium', $node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0]['uri']),
'width' => 220,
'height' => 110,
);
@@ -776,15 +723,15 @@ class ImageFieldDisplayTestCase extends ImageFieldTestCase {
// Add alt/title fields to the image and verify that they are displayed.
$image_info = array(
- 'uri' => $node->{$field_name}[LANGUAGE_NONE][0]['uri'],
+ 'uri' => $node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0]['uri'],
'alt' => $this->randomName(),
'title' => $this->randomName(),
'width' => 40,
'height' => 20,
);
$edit = array(
- $field_name . '[' . LANGUAGE_NONE . '][0][alt]' => $image_info['alt'],
- $field_name . '[' . LANGUAGE_NONE . '][0][title]' => $image_info['title'],
+ $field_name . '[' . LANGUAGE_NOT_SPECIFIED . '][0][alt]' => $image_info['alt'],
+ $field_name . '[' . LANGUAGE_NOT_SPECIFIED . '][0][title]' => $image_info['title'],
);
$this->drupalPost('node/' . $nid . '/edit', $edit, t('Save'));
$default_output = theme('image', $image_info);
@@ -793,8 +740,8 @@ class ImageFieldDisplayTestCase extends ImageFieldTestCase {
// Verify that alt/title longer than allowed results in a validation error.
$test_size = 2000;
$edit = array(
- $field_name . '[' . LANGUAGE_NONE . '][0][alt]' => $this->randomName($test_size),
- $field_name . '[' . LANGUAGE_NONE . '][0][title]' => $this->randomName($test_size),
+ $field_name . '[' . LANGUAGE_NOT_SPECIFIED . '][0][alt]' => $this->randomName($test_size),
+ $field_name . '[' . LANGUAGE_NOT_SPECIFIED . '][0][title]' => $this->randomName($test_size),
);
$this->drupalPost('node/' . $nid . '/edit', $edit, t('Save'));
$this->assertRaw(t('Alternate text cannot be longer than %max characters but is currently %length characters long.', array(
@@ -843,7 +790,7 @@ class ImageFieldDisplayTestCase extends ImageFieldTestCase {
$nid = $this->uploadNodeImage($images[1], $field_name, 'article');
$node = node_load($nid, NULL, TRUE);
$image_info = array(
- 'uri' => $node->{$field_name}[LANGUAGE_NONE][0]['uri'],
+ 'uri' => $node->{$field_name}[LANGUAGE_NOT_SPECIFIED][0]['uri'],
'width' => 40,
'height' => 20,
);
@@ -935,6 +882,7 @@ class ImageFieldValidateTestCase extends ImageFieldTestCase {
* Tests that images have correct dimensions when styled.
*/
class ImageDimensionsUnitTest extends DrupalWebTestCase {
+ protected $profile = 'testing';
public static function getInfo() {
return array(
@@ -945,7 +893,7 @@ class ImageDimensionsUnitTest extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('image_module_test');
+ parent::setUp(array('image', 'image_module_test'));
}
/**
@@ -968,6 +916,10 @@ class ImageDimensionsUnitTest extends DrupalWebTestCase {
'width' => 40,
'height' => 20,
);
+ // Verify that the original image matches the hard-coded values.
+ $image_info = image_get_info($original_uri);
+ $this->assertEqual($image_info['width'], $variables['width']);
+ $this->assertEqual($image_info['height'], $variables['height']);
// Scale an image that is wider than it is high.
$effect = array(
@@ -977,19 +929,19 @@ class ImageDimensionsUnitTest extends DrupalWebTestCase {
'height' => 90,
'upscale' => TRUE,
),
- 'isid' => $style['isid'],
+ 'weight' => 0,
);
- image_effect_save($effect);
+ image_effect_save('test', $effect);
$img_tag = theme_image_style($variables);
- $this->assertEqual($img_tag, '
', t('Expected img tag was found.'));
+ $this->assertEqual($img_tag, '
');
$this->assertFalse(file_exists($generated_uri), t('Generated file does not exist.'));
$this->drupalGet($url);
$this->assertResponse(200, t('Image was generated at the URL.'));
$this->assertTrue(file_exists($generated_uri), t('Generated file does exist after we accessed it.'));
$image_info = image_get_info($generated_uri);
- $this->assertEqual($image_info['width'], 120, t('Expected width was found.'));
- $this->assertEqual($image_info['height'], 60, t('Expected height was found.'));
+ $this->assertEqual($image_info['width'], 120);
+ $this->assertEqual($image_info['height'], 60);
// Rotate 90 degrees anticlockwise.
$effect = array(
@@ -998,19 +950,19 @@ class ImageDimensionsUnitTest extends DrupalWebTestCase {
'degrees' => -90,
'random' => FALSE,
),
- 'isid' => $style['isid'],
+ 'weight' => 1,
);
- image_effect_save($effect);
+ image_effect_save('test', $effect);
$img_tag = theme_image_style($variables);
- $this->assertEqual($img_tag, '
', t('Expected img tag was found.'));
+ $this->assertEqual($img_tag, '
');
$this->assertFalse(file_exists($generated_uri), t('Generated file does not exist.'));
$this->drupalGet($url);
$this->assertResponse(200, t('Image was generated at the URL.'));
$this->assertTrue(file_exists($generated_uri), t('Generated file does exist after we accessed it.'));
$image_info = image_get_info($generated_uri);
- $this->assertEqual($image_info['width'], 60, t('Expected width was found.'));
- $this->assertEqual($image_info['height'], 120, t('Expected height was found.'));
+ $this->assertEqual($image_info['width'], 60);
+ $this->assertEqual($image_info['height'], 120);
// Scale an image that is higher than it is wide (rotated by previous effect).
$effect = array(
@@ -1020,19 +972,19 @@ class ImageDimensionsUnitTest extends DrupalWebTestCase {
'height' => 90,
'upscale' => TRUE,
),
- 'isid' => $style['isid'],
+ 'weight' => 2,
);
- image_effect_save($effect);
+ image_effect_save('test', $effect);
$img_tag = theme_image_style($variables);
- $this->assertEqual($img_tag, '
', t('Expected img tag was found.'));
+ $this->assertEqual($img_tag, '
');
$this->assertFalse(file_exists($generated_uri), t('Generated file does not exist.'));
$this->drupalGet($url);
$this->assertResponse(200, t('Image was generated at the URL.'));
$this->assertTrue(file_exists($generated_uri), t('Generated file does exist after we accessed it.'));
$image_info = image_get_info($generated_uri);
- $this->assertEqual($image_info['width'], 45, t('Expected width was found.'));
- $this->assertEqual($image_info['height'], 90, t('Expected height was found.'));
+ $this->assertEqual($image_info['width'], 45);
+ $this->assertEqual($image_info['height'], 90);
// Test upscale disabled.
$effect = array(
@@ -1042,37 +994,37 @@ class ImageDimensionsUnitTest extends DrupalWebTestCase {
'height' => 200,
'upscale' => FALSE,
),
- 'isid' => $style['isid'],
+ 'weight' => 3,
);
- image_effect_save($effect);
+ image_effect_save('test', $effect);
$img_tag = theme_image_style($variables);
- $this->assertEqual($img_tag, '
', t('Expected img tag was found.'));
+ $this->assertEqual($img_tag, '
');
$this->assertFalse(file_exists($generated_uri), t('Generated file does not exist.'));
$this->drupalGet($url);
$this->assertResponse(200, t('Image was generated at the URL.'));
$this->assertTrue(file_exists($generated_uri), t('Generated file does exist after we accessed it.'));
$image_info = image_get_info($generated_uri);
- $this->assertEqual($image_info['width'], 45, t('Expected width was found.'));
- $this->assertEqual($image_info['height'], 90, t('Expected height was found.'));
+ $this->assertEqual($image_info['width'], 45);
+ $this->assertEqual($image_info['height'], 90);
// Add a desaturate effect.
$effect = array(
'name' => 'image_desaturate',
'data' => array(),
- 'isid' => $style['isid'],
+ 'weight' => 4,
);
- image_effect_save($effect);
+ image_effect_save('test', $effect);
$img_tag = theme_image_style($variables);
- $this->assertEqual($img_tag, '
', t('Expected img tag was found.'));
+ $this->assertEqual($img_tag, '
');
$this->assertFalse(file_exists($generated_uri), t('Generated file does not exist.'));
$this->drupalGet($url);
$this->assertResponse(200, t('Image was generated at the URL.'));
$this->assertTrue(file_exists($generated_uri), t('Generated file does exist after we accessed it.'));
$image_info = image_get_info($generated_uri);
- $this->assertEqual($image_info['width'], 45, t('Expected width was found.'));
- $this->assertEqual($image_info['height'], 90, t('Expected height was found.'));
+ $this->assertEqual($image_info['width'], 45);
+ $this->assertEqual($image_info['height'], 90);
// Add a random rotate effect.
$effect = array(
@@ -1081,12 +1033,12 @@ class ImageDimensionsUnitTest extends DrupalWebTestCase {
'degrees' => 180,
'random' => TRUE,
),
- 'isid' => $style['isid'],
+ 'weight' => 5,
);
- image_effect_save($effect);
+ image_effect_save('test', $effect);
$img_tag = theme_image_style($variables);
- $this->assertEqual($img_tag, '
', t('Expected img tag was found.'));
+ $this->assertEqual($img_tag, '
');
$this->assertFalse(file_exists($generated_uri), t('Generated file does not exist.'));
$this->drupalGet($url);
$this->assertResponse(200, t('Image was generated at the URL.'));
@@ -1101,19 +1053,19 @@ class ImageDimensionsUnitTest extends DrupalWebTestCase {
'height' => 30,
'anchor' => 'center-center',
),
- 'isid' => $style['isid'],
+ 'weight' => 6,
);
- image_effect_save($effect);
+ image_effect_save('test', $effect);
$img_tag = theme_image_style($variables);
- $this->assertEqual($img_tag, '
', t('Expected img tag was found.'));
+ $this->assertEqual($img_tag, '
');
$this->assertFalse(file_exists($generated_uri), t('Generated file does not exist.'));
$this->drupalGet($url);
$this->assertResponse(200, t('Image was generated at the URL.'));
$this->assertTrue(file_exists($generated_uri), t('Generated file does exist after we accessed it.'));
$image_info = image_get_info($generated_uri);
- $this->assertEqual($image_info['width'], 30, t('Expected width was found.'));
- $this->assertEqual($image_info['height'], 30, t('Expected height was found.'));
+ $this->assertEqual($image_info['width'], 30);
+ $this->assertEqual($image_info['height'], 30);
// Rotate to a non-multiple of 90 degrees.
$effect = array(
@@ -1122,30 +1074,30 @@ class ImageDimensionsUnitTest extends DrupalWebTestCase {
'degrees' => 57,
'random' => FALSE,
),
- 'isid' => $style['isid'],
+ 'weight' => 7,
);
- $effect = image_effect_save($effect);
+ $effect = image_effect_save('test', $effect);
$img_tag = theme_image_style($variables);
- $this->assertEqual($img_tag, '
', t('Expected img tag was found.'));
+ $this->assertEqual($img_tag, '
');
$this->assertFalse(file_exists($generated_uri), t('Generated file does not exist.'));
$this->drupalGet($url);
$this->assertResponse(200, t('Image was generated at the URL.'));
$this->assertTrue(file_exists($generated_uri), t('Generated file does exist after we accessed it.'));
- image_effect_delete($effect);
+ image_effect_delete('test', $effect);
// Ensure that an effect with no dimensions callback unsets the dimensions.
// This ensures compatibility with 7.0 contrib modules.
$effect = array(
'name' => 'image_module_test_null',
'data' => array(),
- 'isid' => $style['isid'],
+ 'weight' => 8,
);
- image_effect_save($effect);
+ image_effect_save('test', $effect);
$img_tag = theme_image_style($variables);
- $this->assertEqual($img_tag, '
', t('Expected img tag was found.'));
+ $this->assertEqual($img_tag, '
');
}
}
diff --git a/core/modules/locale/locale.admin.inc b/core/modules/locale/locale.admin.inc
index 2c78e17..321b8ce 100644
--- a/core/modules/locale/locale.admin.inc
+++ b/core/modules/locale/locale.admin.inc
@@ -16,7 +16,7 @@ function language_negotiation_configure_form() {
'#theme' => 'language_negotiation_configure_form',
'#language_types' => language_types_get_configurable(FALSE),
'#language_types_info' => language_types_info(),
- '#language_providers' => language_negotiation_info(),
+ '#language_negotiation_info' => language_negotiation_info(),
);
foreach ($form['#language_types'] as $type) {
@@ -33,7 +33,7 @@ function language_negotiation_configure_form() {
}
/**
- * Helper function to build a language provider table.
+ * Builds a language negotion method configuration table.
*/
function language_negotiation_configure_form_table(&$form, $type) {
$info = $form['#language_types_info'][$type];
@@ -42,74 +42,74 @@ function language_negotiation_configure_form_table(&$form, $type) {
'#title' => t('@type language detection', array('@type' => $info['name'])),
'#tree' => TRUE,
'#description' => $info['description'],
- '#language_providers' => array(),
+ '#language_negotiation_info' => array(),
'#show_operations' => FALSE,
'weight' => array('#tree' => TRUE),
'enabled' => array('#tree' => TRUE),
);
- $language_providers = $form['#language_providers'];
- $enabled_providers = variable_get("language_negotiation_$type", array());
- $providers_weight = variable_get("locale_language_providers_weight_$type", array());
+ $negotiation_info = $form['#language_negotiation_info'];
+ $enabled_methods = variable_get("language_negotiation_$type", array());
+ $methods_weight = variable_get("locale_language_negotiation_methods_weight_$type", array());
- // Add missing data to the providers lists.
- foreach ($language_providers as $id => $provider) {
- if (!isset($providers_weight[$id])) {
- $providers_weight[$id] = language_provider_weight($provider);
+ // Add missing data to the methods lists.
+ foreach ($negotiation_info as $method_id => $method) {
+ if (!isset($methods_weight[$method_id])) {
+ $methods_weight[$method_id] = isset($method['weight']) ? $method['weight'] : 0;
}
}
- // Order providers list by weight.
- asort($providers_weight);
+ // Order methods list by weight.
+ asort($methods_weight);
- foreach ($providers_weight as $id => $weight) {
- // A language provider might be no more available if the defining module has
+ foreach ($methods_weight as $method_id => $weight) {
+ // A language method might be no more available if the defining module has
// been disabled after the last configuration saving.
- if (!isset($language_providers[$id])) {
+ if (!isset($negotiation_info[$method_id])) {
continue;
}
- $enabled = isset($enabled_providers[$id]);
- $provider = $language_providers[$id];
+ $enabled = isset($enabled_methods[$method_id]);
+ $method = $negotiation_info[$method_id];
- // List the provider only if the current type is defined in its 'types' key.
+ // List the method only if the current type is defined in its 'types' key.
// If it is not defined default to all the configurable language types.
- $types = array_flip(isset($provider['types']) ? $provider['types'] : $form['#language_types']);
+ $types = array_flip(isset($method['types']) ? $method['types'] : $form['#language_types']);
if (isset($types[$type])) {
- $table_form['#language_providers'][$id] = $provider;
- $provider_name = check_plain($provider['name']);
+ $table_form['#language_negotiation_info'][$method_id] = $method;
+ $method_name = check_plain($method['name']);
- $table_form['weight'][$id] = array(
+ $table_form['weight'][$method_id] = array(
'#type' => 'weight',
- '#title' => t('Weight for !title language detection method', array('!title' => drupal_strtolower($provider_name))),
+ '#title' => t('Weight for !title language detection method', array('!title' => drupal_strtolower($method_name))),
'#title_display' => 'invisible',
'#default_value' => $weight,
- '#attributes' => array('class' => array("language-provider-weight-$type")),
+ '#attributes' => array('class' => array("language-method-weight-$type")),
);
- $table_form['title'][$id] = array('#markup' => $provider_name);
+ $table_form['title'][$method_id] = array('#markup' => $method_name);
- $table_form['enabled'][$id] = array(
+ $table_form['enabled'][$method_id] = array(
'#type' => 'checkbox',
- '#title' => t('Enable !title language detection method', array('!title' => drupal_strtolower($provider_name))),
+ '#title' => t('Enable !title language detection method', array('!title' => drupal_strtolower($method_name))),
'#title_display' => 'invisible',
'#default_value' => $enabled,
);
- if ($id === LANGUAGE_NEGOTIATION_DEFAULT) {
- $table_form['enabled'][$id]['#default_value'] = TRUE;
- $table_form['enabled'][$id]['#attributes'] = array('disabled' => 'disabled');
+ if ($method_id === LANGUAGE_NEGOTIATION_DEFAULT) {
+ $table_form['enabled'][$method_id]['#default_value'] = TRUE;
+ $table_form['enabled'][$method_id]['#attributes'] = array('disabled' => 'disabled');
}
- $table_form['description'][$id] = array('#markup' => filter_xss_admin($provider['description']));
+ $table_form['description'][$method_id] = array('#markup' => filter_xss_admin($method['description']));
$config_op = array();
- if (isset($provider['config'])) {
- $config_op = array('#type' => 'link', '#title' => t('Configure'), '#href' => $provider['config']);
+ if (isset($method['config'])) {
+ $config_op = array('#type' => 'link', '#title' => t('Configure'), '#href' => $method['config']);
// If there is at least one operation enabled show the operation column.
$table_form['#show_operations'] = TRUE;
}
- $table_form['operation'][$id] = $config_op;
+ $table_form['operation'][$method_id] = $config_op;
}
}
@@ -169,12 +169,12 @@ function theme_language_negotiation_configure_form($variables) {
$variables = array(
'header' => $header,
'rows' => $rows,
- 'attributes' => array('id' => "language-negotiation-providers-$type"),
+ 'attributes' => array('id' => "language-negotiation-methods-$type"),
);
$table = theme('table', $variables);
$table .= drupal_render_children($form[$type]);
- drupal_add_tabledrag("language-negotiation-providers-$type", 'order', 'sibling', "language-provider-weight-$type");
+ drupal_add_tabledrag("language-negotiation-methods-$type", 'order', 'sibling', "language-method-weight-$type");
$output .= '
' . $title . $description . $table . '
';
}
@@ -190,21 +190,19 @@ function language_negotiation_configure_form_submit($form, &$form_state) {
$configurable_types = $form['#language_types'];
foreach ($configurable_types as $type) {
- $negotiation = array();
- $enabled_providers = $form_state['values'][$type]['enabled'];
- $enabled_providers[LANGUAGE_NEGOTIATION_DEFAULT] = TRUE;
- $providers_weight = $form_state['values'][$type]['weight'];
-
- foreach ($providers_weight as $id => $weight) {
- if ($enabled_providers[$id]) {
- $provider = $form[$type]['#language_providers'][$id];
- $provider['weight'] = $weight;
- $negotiation[$id] = $provider;
+ $method_weights = array();
+ $enabled_methods = $form_state['values'][$type]['enabled'];
+ $enabled_methods[LANGUAGE_NEGOTIATION_DEFAULT] = TRUE;
+ $method_weights_input = $form_state['values'][$type]['weight'];
+
+ foreach ($method_weights_input as $method_id => $weight) {
+ if ($enabled_methods[$method_id]) {
+ $method_weights[$method_id] = $weight;
}
}
- language_negotiation_set($type, $negotiation);
- variable_set("locale_language_providers_weight_$type", $providers_weight);
+ language_negotiation_set($type, $method_weights);
+ variable_set("locale_language_negotiation_methods_weight_$type", $method_weights_input);
}
// Update non-configurable language types and the related language negotiation
@@ -216,7 +214,7 @@ function language_negotiation_configure_form_submit($form, &$form_state) {
}
/**
- * Builds the URL language provider configuration form.
+ * Builds the URL language negotiation method configuration form.
*/
function language_negotiation_configure_url_form($form, &$form_state) {
$form['locale_language_negotiation_url_part'] = array(
@@ -287,7 +285,7 @@ function language_negotiation_configure_url_form($form, &$form_state) {
}
/**
- * Validation handler for url provider configuration.
+ * Validates the URL language negotiation method configuration.
*
* Validate that the prefixes and domains are unique, and make sure that
* the prefix and domain are only blank for the default.
@@ -330,10 +328,23 @@ function language_negotiation_configure_url_form_validate($form, &$form_state) {
form_error($form['domain'][$langcode], t('The domain for %language, %value, is not unique.', array('%language' => $language->name, '%value' => $value)));
}
}
+
+ // Domain names should not contain protocol and/or ports.
+ foreach ($languages as $langcode => $name) {
+ $value = $form_state['values']['domain'][$langcode];
+ if (!empty($value)) {
+ // Ensure we have a protocol but only one protocol in the setting for
+ // parse_url() checking against the hostname.
+ $host = 'http://' . str_replace(array('http://', 'https://'), '', $value);
+ if (parse_url($host, PHP_URL_HOST) != $value) {
+ form_error($form['domain'][$langcode], t('The domain for %language may only contain the domain name, not a protocol and/or port.', array( '%language' => $name)));
+ }
+ }
+ }
}
/**
- * Save URL negotiation provider settings.
+ * Saves the URL language negotiation method settings.
*/
function language_negotiation_configure_url_form_submit($form, &$form_state) {
@@ -348,7 +359,7 @@ function language_negotiation_configure_url_form_submit($form, &$form_state) {
}
/**
- * The URL language provider configuration form.
+ * Builds the session language negotiation method configuration form.
*/
function language_negotiation_configure_session_form($form, &$form_state) {
$form['locale_language_negotiation_session_param'] = array(
diff --git a/core/modules/locale/locale.install b/core/modules/locale/locale.install
index d3f0152..11d1873 100644
--- a/core/modules/locale/locale.install
+++ b/core/modules/locale/locale.install
@@ -17,14 +17,14 @@ function locale_install() {
// We cannot rely on language negotiation hooks here, because locale module is
// not enabled yet. Therefore language_negotiation_set() cannot be used.
$info = locale_language_negotiation_info();
- $provider = $info[LANGUAGE_NEGOTIATION_URL];
- $provider_fields = array('callbacks', 'file', 'cache');
+ $method = $info[LANGUAGE_NEGOTIATION_URL];
+ $method_fields = array('callbacks', 'file', 'cache');
$negotiation = array();
// Store only the needed data.
- foreach ($provider_fields as $field) {
- if (isset($provider[$field])) {
- $negotiation[LANGUAGE_NEGOTIATION_URL][$field] = $provider[$field];
+ foreach ($method_fields as $field) {
+ if (isset($method[$field])) {
+ $negotiation[LANGUAGE_NEGOTIATION_URL][$field] = $method[$field];
}
}
@@ -99,7 +99,7 @@ function locale_uninstall() {
foreach (language_types_get_all() as $type) {
variable_del("language_negotiation_$type");
- variable_del("locale_language_providers_weight_$type");
+ variable_del("locale_language_negotiation_methods_weight_$type");
}
// Remove all node type language variables. Node module might have been
@@ -176,20 +176,8 @@ function locale_schema() {
'default' => '',
'description' => 'Language code. References {language}.langcode.',
),
- 'plid' => array(
- 'type' => 'int',
- 'not null' => TRUE, // This should be NULL for no referenced string, not zero.
- 'default' => 0,
- 'description' => 'Parent lid (lid of the previous string in the plural chain) in case of plural strings. References {locales_source}.lid.',
- ),
- 'plural' => array(
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- 'description' => 'Plural index number in case of plural strings.',
- ),
),
- 'primary key' => array('language', 'lid', 'plural'),
+ 'primary key' => array('language', 'lid'),
'foreign keys' => array(
'locales_source' => array(
'table' => 'locales_source',
@@ -198,8 +186,6 @@ function locale_schema() {
),
'indexes' => array(
'lid' => array('lid'),
- 'plid' => array('plid'),
- 'plural' => array('plural'),
),
);
@@ -317,6 +303,186 @@ function locale_update_8002() {
}
/**
+ * Converts language domains to new format.
+ */
+function locale_update_8003() {
+ $message = '';
+ $domains = variable_get('locale_language_negotiation_url_domains', array());
+ // $used_domains keeps track of the domain names in use.
+ $used_domains = array();
+ foreach ($domains as $langcode => $domain) {
+ // Domain names can not contain protocol and/or ports.
+ if (!empty($domain)) {
+ $host = 'http://' . str_replace(array('http://', 'https://'), '', $domain);
+ if (parse_url($host, PHP_URL_HOST) != $domain) {
+ $domains[$langcode] = parse_url($host, PHP_URL_HOST);
+ }
+ if (array_key_exists($domain, $used_domains)) {
+ if (empty($message)) {
+ $message = 'Some languages are using the same domain name, you should change these domain names at ' . l('URL language detection configuration', 'admin/config/regional/language/configure/url' . '.');
+ }
+ }
+ else {
+ $used_domains[$domain] = $domain;
+ }
+ }
+ }
+ variable_set('locale_language_negotiation_url_domains', $domains);
+
+ if (!empty($message)) {
+ return $message;
+ }
+}
+
+/**
+ * Rename language providers to language negotiation methods.
+ */
+function locale_update_8004() {
+ $types = variable_get('language_types', NULL);
+ if (!empty($types)) {
+ foreach ($types as $type => $configurable) {
+ // Rename the negotiation and language switch callback keys.
+ $negotiation = variable_get('language_negotiation_' . $type, NULL);
+ if (!empty($negotiation)) {
+ foreach ($negotiation as $method_id => &$method) {
+ $method['callbacks']['negotiation'] = $method['callbacks']['language'];
+ unset($method['callbacks']['language']);
+ if (isset($method['callbacks']['switcher'])) {
+ $method['callbacks']['language_switch'] = $method['callbacks']['switcher'];
+ unset($method['callbacks']['switcher']);
+ }
+ }
+ variable_set('language_negotiation_' . $type, $negotiation);
+ }
+
+ // Rename the language negotiation methods weight variable.
+ $weight = variable_get('locale_language_providers_weight_' . $type , NULL);
+ if ($weight !== NULL) {
+ variable_set('locale_language_negotiation_methods_weight_' . $type , $weight);
+ variable_del('locale_language_providers_weight_' . $type);
+ }
+ }
+ }
+}
+
+/**
+ * Update plural interface translations to new format.
+ *
+ * See http://drupal.org/node/532512#comment-5679184 for the details of the
+ * structures handled in this update.
+ */
+function locale_update_8005() {
+ // Collect all LIDs that are sources to plural variants.
+ $results = db_query("SELECT lid, plid FROM {locales_target} WHERE plural <> 0");
+ $plural_lids = array();
+ foreach ($results as $row) {
+ // Need to collect both LID and PLID. The LID for the first (singular)
+ // string can only be retrieved from the first plural's PLID given no
+ // other indication. The last plural variant is never referenced, so we
+ // need to store the LID directly for that. We never know whether we are
+ // on the last plural though, so we always remember LID too.
+ $plural_lids[] = $row->lid;
+ $plural_lids[] = $row->plid;
+ }
+ $plural_lids = array_unique($plural_lids);
+
+ // Look up all translations for these source strings. Ordering by language
+ // will group the strings by language, the 'plid' order will get the
+ // strings in singular/plural order and 'plural' will get them in precise
+ // sequential order needed.
+ $results = db_query("SELECT s.lid, s.source, t.translation, t.plid, t.plural, t.language FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid WHERE s.lid IN (:lids) ORDER BY t.language, t.plid, t.plural", array(':lids' => $plural_lids));
+
+ // Collect the strings into an array and combine values as we go.
+ $strings = array();
+ $parents_to_sources = array();
+ $remove_lids = array();
+ foreach ($results as $child) {
+ $strings[$child->language][$child->lid] = array(
+ 'source' => array($child->source),
+ 'translation' => array($child->translation),
+ );
+
+ if (empty($child->plid)) {
+ // Non-children strings point to themselves as parents. This makes it
+ // easy to look up the utmost parents for any plurals.
+ $parents_to_sources[$child->lid] = $child->lid;
+ }
+ else {
+ // Children strings point to their utmost parents. Because we get data
+ // in PLID order, we can ensure that all previous parents have data now,
+ // so we can just copy the parent's data about their parent, etc.
+ $parents_to_sources[$child->lid] = $parents_to_sources[$child->plid];
+
+ // Append translation to the utmost parent's translation string.
+ $utmost_parent = &$strings[$child->language][$parents_to_sources[$child->plid]];
+ // Drop the Drupal-specific numbering scheme from the end of plural
+ // formulas.
+ $utmost_parent['translation'][] = str_replace('@count[' . $child->plural .']', '@count', $child->translation);
+ if (count($utmost_parent['source']) < 2) {
+ // Append source to the utmost parent's source string only if it is the
+ // plural variant. Further Drupal specific plural variants are not to be
+ // retained for source strings.
+ $utmost_parent['source'][] = $child->source;
+ }
+
+ // All plural variant LIDs are to be removed with their translations.
+ // Only the singular LIDs will be kept.
+ $remove_lids[] = $child->lid;
+ }
+ }
+
+ // Do updates for all source strings and all translations.
+ $updated_sources = array();
+ foreach ($strings as $langcode => $translations) {
+ foreach($translations as $lid => $translation) {
+ if (!in_array($lid, $updated_sources)) {
+ // Only update source string if not yet updated. We merged these within
+ // the translation lookups because plural information was only avilable
+ // with the translation, but we don't need to save it again for every
+ // language.
+ db_update('locales_source')
+ ->fields(array(
+ 'source' => implode(LOCALE_PLURAL_DELIMITER, $translation['source']),
+ ))
+ ->condition('lid', $lid)
+ ->execute();
+ $updated_sources[] = $lid;
+ }
+ db_update('locales_target')
+ ->fields(array(
+ 'translation' => implode(LOCALE_PLURAL_DELIMITER, $translation['translation']),
+ ))
+ ->condition('lid', $lid)
+ ->condition('language', $langcode)
+ ->execute();
+ }
+ }
+
+ // Remove all plural LIDs from source and target. only keep those which were
+ // originally used for the singular strings (now updated to contain the
+ // serialized version of plurals).
+ $remove_lids = array_unique($remove_lids);
+ db_delete('locales_source')
+ ->condition('lid', $remove_lids, 'IN')
+ ->execute();
+ db_delete('locales_target')
+ ->condition('lid', $remove_lids, 'IN')
+ ->execute();
+
+ // Drop the primary key because it contains 'plural'.
+ db_drop_primary_key('locales_target');
+
+ // Remove the 'plid' and 'plural' columns and indexes.
+ db_drop_index('locales_target', 'plid');
+ db_drop_field('locales_target', 'plid');
+ db_drop_index('locales_target', 'plural');
+ db_drop_field('locales_target', 'plural');
+
+ // Add back a primary key without 'plural'.
+ db_add_primary_key('locales_target', array('language', 'lid'));
+}
+
+/**
* @} End of "addtogroup updates-7.x-to-8.x"
* The next series of updates should start at 9000.
*/
diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module
index 7cadf53..6b9ab6e 100644
--- a/core/modules/locale/locale.module
+++ b/core/modules/locale/locale.module
@@ -207,6 +207,7 @@ function locale_permission() {
return array(
'translate interface' => array(
'title' => t('Translate interface texts'),
+ 'restrict access' => TRUE,
),
);
}
@@ -230,23 +231,47 @@ function locale_language_selector_form($user) {
$names[$langcode] = $item->name;
}
// Get language negotiation settings.
- $mode = language_negotiation_get(LANGUAGE_TYPE_INTERFACE) != LANGUAGE_NEGOTIATION_DEFAULT;
+ $mode = language_negotiation_method_get_first(LANGUAGE_TYPE_INTERFACE) != LANGUAGE_NEGOTIATION_DEFAULT;
$form['locale'] = array(
'#type' => 'fieldset',
'#title' => t('Language settings'),
'#weight' => 1,
);
- $form['locale']['language'] = array(
+ $form['locale']['preferred_langcode'] = array(
'#type' => (count($names) <= 5 ? 'radios' : 'select'),
'#title' => t('Language'),
'#default_value' => $user_preferred_language->langcode,
'#options' => $names,
- '#description' => $mode ? t("This account's default language for e-mails, and preferred language for site presentation.") : t("This account's default language for e-mails."),
+ '#description' => $mode ? t("This account's preferred language for e-mails and site presentation.") : t("This account's preferred language for e-mails."),
+ );
+ // User entities contain both a langcode property (for identifying the
+ // language of the entity data) and a preferred_langcode property (see above).
+ // Rather than provide a UI forcing the user to choose both separately,
+ // assume that the user profile data is in the user's preferred language. This
+ // element provides that synchronization. For use-cases where this
+ // synchronization is not desired, a module can alter or remove this element.
+ $form['locale']['langcode'] = array(
+ '#type' => 'value',
+ '#value_callback' => '_locale_language_selector_langcode_value',
+ // For the synchronization to work, this element must have a larger weight
+ // than the preferred_langcode element. Set a large weight here in case
+ // a module alters the weight of the other element.
+ '#weight' => 100,
);
return $form;
}
/**
+ * Sets the value of the user register and profile forms' langcode element.
+ *
+ * @see locale_language_selector_form()
+ */
+function _locale_language_selector_langcode_value($element, $input, &$form_state) {
+ $form_state['complete_form']['locale']['preferred_langcode']['#description'] .= ' ' . t("This is also assumed to be the primary language of this account's profile information.");
+ return $form_state['values']['preferred_langcode'];
+}
+
+/**
* Implements hook_form_alter().
*
* Adds language fields to user forms.
@@ -390,8 +415,9 @@ function locale_entity_info_alter(&$entity_info) {
* language negotiated value. It is used by the Field API to determine the
* display language for fields if no explicit value is specified.
* - URL language is by default non-configurable and is determined through the
- * URL language provider or the URL fallback provider if no language can be
- * detected. It is used by l() as the default language if none is specified.
+ * URL language negotiation method or the URL fallback language negotiation
+ * method if no language can be detected. It is used by l() as the default
+ * language if none is specified.
*/
function locale_language_types_info() {
require_once DRUPAL_ROOT . '/core/includes/locale.inc';
@@ -417,13 +443,13 @@ function locale_language_types_info() {
function locale_language_negotiation_info() {
require_once DRUPAL_ROOT . '/core/includes/locale.inc';
$file = '/core/includes/locale.inc';
- $providers = array();
+ $negotiation_info = array();
- $providers[LANGUAGE_NEGOTIATION_URL] = array(
+ $negotiation_info[LANGUAGE_NEGOTIATION_URL] = array(
'types' => array(LANGUAGE_TYPE_CONTENT, LANGUAGE_TYPE_INTERFACE, LANGUAGE_TYPE_URL),
'callbacks' => array(
- 'language' => 'locale_language_from_url',
- 'switcher' => 'locale_language_switcher_url',
+ 'negotiation' => 'locale_language_from_url',
+ 'language_switch' => 'locale_language_switcher_url',
'url_rewrite' => 'locale_language_url_rewrite_url',
),
'file' => $file,
@@ -433,10 +459,10 @@ function locale_language_negotiation_info() {
'config' => 'admin/config/regional/language/detection/url',
);
- $providers[LANGUAGE_NEGOTIATION_SESSION] = array(
+ $negotiation_info[LANGUAGE_NEGOTIATION_SESSION] = array(
'callbacks' => array(
- 'language' => 'locale_language_from_session',
- 'switcher' => 'locale_language_switcher_session',
+ 'negotiation' => 'locale_language_from_session',
+ 'language_switch' => 'locale_language_switcher_session',
'url_rewrite' => 'locale_language_url_rewrite_session',
),
'file' => $file,
@@ -446,16 +472,16 @@ function locale_language_negotiation_info() {
'config' => 'admin/config/regional/language/detection/session',
);
- $providers[LANGUAGE_NEGOTIATION_USER] = array(
- 'callbacks' => array('language' => 'locale_language_from_user'),
+ $negotiation_info[LANGUAGE_NEGOTIATION_USER] = array(
+ 'callbacks' => array('negotiation' => 'locale_language_from_user'),
'file' => $file,
'weight' => -4,
'name' => t('User'),
'description' => t("Follow the user's language preference."),
);
- $providers[LANGUAGE_NEGOTIATION_BROWSER] = array(
- 'callbacks' => array('language' => 'locale_language_from_browser'),
+ $negotiation_info[LANGUAGE_NEGOTIATION_BROWSER] = array(
+ 'callbacks' => array('negotiation' => 'locale_language_from_browser'),
'file' => $file,
'weight' => -2,
'cache' => 0,
@@ -463,25 +489,25 @@ function locale_language_negotiation_info() {
'description' => t("Determine the language from the browser's language settings."),
);
- $providers[LANGUAGE_NEGOTIATION_INTERFACE] = array(
+ $negotiation_info[LANGUAGE_NEGOTIATION_INTERFACE] = array(
'types' => array(LANGUAGE_TYPE_CONTENT),
- 'callbacks' => array('language' => 'locale_language_from_interface'),
+ 'callbacks' => array('negotiation' => 'locale_language_from_interface'),
'file' => $file,
'weight' => 8,
'name' => t('Interface'),
'description' => t('Use the detected interface language.'),
);
- $providers[LANGUAGE_NEGOTIATION_URL_FALLBACK] = array(
+ $negotiation_info[LANGUAGE_NEGOTIATION_URL_FALLBACK] = array(
'types' => array(LANGUAGE_TYPE_URL),
- 'callbacks' => array('language' => 'locale_language_url_fallback'),
+ 'callbacks' => array('negotiation' => 'locale_language_url_fallback'),
'file' => $file,
'weight' => 8,
'name' => t('URL fallback'),
'description' => t('Use an already detected language for URLs if none is found.'),
);
- return $providers;
+ return $negotiation_info;
}
/**
@@ -901,7 +927,7 @@ function locale_block_view($type) {
if (isset($links->links)) {
drupal_add_css(drupal_get_path('module', 'locale') . '/locale.css');
- $class = "language-switcher-{$links->provider}";
+ $class = "language-switcher-{$links->method_id}";
$variables = array('links' => $links->links, 'attributes' => array('class' => array($class)));
$block['content'] = theme('links__locale_block', $variables);
$block['subject'] = t('Languages');
@@ -938,16 +964,16 @@ function locale_url_outbound_alter(&$path, &$options, $original_path) {
include_once DRUPAL_ROOT . '/core/includes/language.inc';
foreach (language_types_get_configurable() as $type) {
- // Get url rewriter callbacks only from enabled language providers.
+ // Get URL rewriter callbacks only from enabled language methods.
$negotiation = variable_get("language_negotiation_$type", array());
- foreach ($negotiation as $id => $provider) {
- if (isset($provider['callbacks']['url_rewrite'])) {
- if (isset($provider['file'])) {
- require_once DRUPAL_ROOT . '/' . $provider['file'];
+ foreach ($negotiation as $method_id => $method) {
+ if (isset($method['callbacks']['url_rewrite'])) {
+ if (isset($method['file'])) {
+ require_once DRUPAL_ROOT . '/' . $method['file'];
}
// Avoid duplicate callback entries.
- $callbacks[$provider['callbacks']['url_rewrite']] = TRUE;
+ $callbacks[$method['callbacks']['url_rewrite']] = TRUE;
}
}
}
@@ -1087,7 +1113,7 @@ function locale_form_system_file_system_settings_alter(&$form, $form_state) {
* Implements MODULE_preprocess_HOOK().
*/
function locale_preprocess_node(&$variables) {
- if ($variables['langcode'] != LANGUAGE_NONE) {
+ if ($variables['langcode'] != LANGUAGE_NOT_SPECIFIED) {
global $language_interface;
$node_language = language_load($variables['langcode']);
diff --git a/core/modules/locale/locale.pages.inc b/core/modules/locale/locale.pages.inc
index e41bae5..0d59f42 100644
--- a/core/modules/locale/locale.pages.inc
+++ b/core/modules/locale/locale.pages.inc
@@ -92,7 +92,7 @@ function _locale_translate_seek() {
$rows = array();
foreach ($strings as $lid => $string) {
$rows[] = array(
- array('data' => check_plain(truncate_utf8($string['source'], 150, FALSE, TRUE)) . '
' . $string['location'] . ''),
+ array('data' => check_plain(truncate_utf8(str_replace(LOCALE_PLURAL_DELIMITER, ', ', $string['source']), 150, FALSE, TRUE)) . '
' . $string['location'] . ''),
$string['context'],
array('data' => _locale_translate_language_list($string['languages'], $limit_language), 'align' => 'center'),
array('data' => l(t('edit'), "admin/config/regional/translate/edit/$lid", array('query' => drupal_get_destination())), 'class' => array('nowrap')),
@@ -278,13 +278,37 @@ function locale_translate_edit_form($form, &$form_state, $lid) {
drupal_set_message(t('String not found.'), 'error');
drupal_goto('admin/config/regional/translate/translate');
}
-
- // Add original text to the top and some values for form altering.
- $form['original'] = array(
- '#type' => 'item',
- '#title' => t('Original text'),
- '#markup' => check_plain(wordwrap($source->source, 0)),
- );
+ // Split source to work with plural values.
+ $source_array = explode(LOCALE_PLURAL_DELIMITER, $source->source);
+ if (count($source_array) == 1) {
+ // Add original text value and mark as non-plural.
+ $form['plural'] = array(
+ '#type' => 'value',
+ '#value' => 0
+ );
+ $form['original'] = array(
+ '#type' => 'item',
+ '#title' => t('Original text'),
+ '#markup' => check_plain($source_array[0]),
+ );
+ }
+ else {
+ // Add original text value and mark as plural.
+ $form['plural'] = array(
+ '#type' => 'value',
+ '#value' => 1
+ );
+ $form['original_singular'] = array(
+ '#type' => 'item',
+ '#title' => t('Original singular form'),
+ '#markup' => check_plain($source_array[0]),
+ );
+ $form['original_plural'] = array(
+ '#type' => 'item',
+ '#title' => t('Original plural form'),
+ '#markup' => check_plain($source_array[1]),
+ );
+ }
if (!empty($source->context)) {
$form['context'] = array(
'#type' => 'item',
@@ -307,22 +331,68 @@ function locale_translate_edit_form($form, &$form_state, $lid) {
if (!locale_translate_english()) {
unset($languages['en']);
}
- $form['translations'] = array('#tree' => TRUE);
+ // Store languages to iterate for validation and submission of the form.
+ $form_state['langcodes'] = array_keys($languages);
+ $plural_formulas = variable_get('locale_translation_plurals', array());
+
+ $form['translations'] = array(
+ '#type' => 'vertical_tabs',
+ '#tree' => TRUE
+ );
+
// Approximate the number of rows to use in the default textarea.
- $rows = min(ceil(str_word_count($source->source) / 12), 10);
+ $rows = min(ceil(str_word_count($source_array[0]) / 12), 10);
foreach ($languages as $langcode => $language) {
$form['translations'][$langcode] = array(
- '#type' => 'textarea',
+ '#type' => 'fieldset',
'#title' => $language->name,
- '#rows' => $rows,
- '#default_value' => '',
);
+ if (empty($form['plural']['#value'])) {
+ $form['translations'][$langcode][0] = array(
+ '#type' => 'textarea',
+ '#title' => $language->name,
+ '#rows' => $rows,
+ '#default_value' => '',
+ );
+ }
+ else {
+ // Dealing with plural strings.
+ if (isset($plural_formulas[$langcode]['plurals']) && $plural_formulas[$langcode]['plurals'] > 1) {
+ // Add a textarea for each plural variant.
+ for ($i = 0; $i < $plural_formulas[$langcode]['plurals']; $i++) {
+ $form['translations'][$langcode][$i] = array(
+ '#type' => 'textarea',
+ '#title' => ($i == 0 ? t('Singular form') : format_plural($i, 'First plural form', '@count. plural form')),
+ '#rows' => $rows,
+ '#default_value' => '',
+ );
+ }
+ }
+ else {
+ // Fallback for unknown number of plurals.
+ $form['translations'][$langcode][0] = array(
+ '#type' => 'textarea',
+ '#title' => t('Sigular form'),
+ '#rows' => $rows,
+ '#default_value' => '',
+ );
+ $form['translations'][$langcode][1] = array(
+ '#type' => 'textarea',
+ '#title' => t('Plural form'),
+ '#rows' => $rows,
+ '#default_value' => '',
+ );
+ }
+ }
}
// Fetch translations and fill in default values in the form.
$result = db_query("SELECT DISTINCT translation, language FROM {locales_target} WHERE lid = :lid", array(':lid' => $lid));
foreach ($result as $translation) {
- $form['translations'][$translation->language]['#default_value'] = $translation->translation;
+ $translation_array = explode(LOCALE_PLURAL_DELIMITER, $translation->translation);
+ for ($i = 0; $i < count($translation_array); $i++) {
+ $form['translations'][$translation->language][$i]['#default_value'] = $translation_array[$i];
+ }
}
$form['actions'] = array('#type' => 'actions');
@@ -334,10 +404,12 @@ function locale_translate_edit_form($form, &$form_state, $lid) {
* Validate string editing form submissions.
*/
function locale_translate_edit_form_validate($form, &$form_state) {
- foreach ($form_state['values']['translations'] as $key => $value) {
- if (!locale_string_is_safe($value)) {
- form_set_error('translations', t('The submitted string contains disallowed HTML: %string', array('%string' => $value)));
- watchdog('locale', 'Attempted submission of a translation string with disallowed HTML: %string', array('%string' => $value), WATCHDOG_WARNING);
+ foreach ($form_state['langcodes'] as $langcode) {
+ foreach ($form_state['values']['translations'][$langcode] as $key => $value) {
+ if (!locale_string_is_safe($value)) {
+ form_set_error("translations][$langcode][$key", t('The submitted string contains disallowed HTML: %string', array('%string' => $value)));
+ watchdog('locale', 'Attempted submission of a translation string with disallowed HTML: %string', array('%string' => $value), WATCHDOG_WARNING);
+ }
}
}
}
@@ -349,9 +421,19 @@ function locale_translate_edit_form_validate($form, &$form_state) {
*/
function locale_translate_edit_form_submit($form, &$form_state) {
$lid = $form_state['values']['lid'];
- foreach ($form_state['values']['translations'] as $key => $value) {
- $translation = db_query("SELECT translation FROM {locales_target} WHERE lid = :lid AND language = :language", array(':lid' => $lid, ':language' => $key))->fetchField();
- if (!empty($value)) {
+ foreach ($form_state['langcodes'] as $langcode) {
+ // Serialize plural variants in one string by LOCALE_PLURAL_DELIMITER.
+ $value = implode(LOCALE_PLURAL_DELIMITER, $form_state['values']['translations'][$langcode]);
+ $translation = db_query("SELECT translation FROM {locales_target} WHERE lid = :lid AND language = :language", array(':lid' => $lid, ':language' => $langcode))->fetchField();
+ // No translation when all strings are empty.
+ $has_translation = FALSE;
+ foreach ($form_state['values']['translations'][$langcode] as $string) {
+ if (!empty($string)) {
+ $has_translation = TRUE;
+ break;
+ }
+ }
+ if ($has_translation) {
// Only update or insert if we have a value to use.
if (!empty($translation)) {
db_update('locales_target')
@@ -359,7 +441,7 @@ function locale_translate_edit_form_submit($form, &$form_state) {
'translation' => $value,
))
->condition('lid', $lid)
- ->condition('language', $key)
+ ->condition('language', $langcode)
->execute();
}
else {
@@ -367,7 +449,7 @@ function locale_translate_edit_form_submit($form, &$form_state) {
->fields(array(
'lid' => $lid,
'translation' => $value,
- 'language' => $key,
+ 'language' => $langcode,
))
->execute();
}
@@ -376,12 +458,12 @@ function locale_translate_edit_form_submit($form, &$form_state) {
// Empty translation entered: remove existing entry from database.
db_delete('locales_target')
->condition('lid', $lid)
- ->condition('language', $key)
+ ->condition('language', $langcode)
->execute();
}
// Force JavaScript translation file recreation for this language.
- _locale_invalidate_js($key);
+ _locale_invalidate_js($langcode);
}
drupal_set_message(t('The string has been saved.'));
diff --git a/core/modules/locale/locale.test b/core/modules/locale/locale.test
index 208c5e6..f2395ad 100644
--- a/core/modules/locale/locale.test
+++ b/core/modules/locale/locale.test
@@ -56,7 +56,7 @@ class LocaleConfigurationTest extends DrupalWebTestCase {
'predefined_langcode' => 'fr',
);
$this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
- $this->assertText('fr', t('Language added successfully.'));
+ $this->assertText('French');
$this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
// Check if the Default English language has no path prefix.
@@ -267,8 +267,8 @@ class LocaleTranslationFunctionalTest extends DrupalWebTestCase {
$this->clickLink(t('edit'));
$string_edit_url = $this->getUrl();
$edit = array(
- "translations[$langcode]" => $translation,
- 'translations[en]' => $translation_to_en,
+ "translations[$langcode][0]" => $translation,
+ 'translations[en][0]' => $translation_to_en,
);
$this->drupalPost(NULL, $edit, t('Save translations'));
$this->assertText(t('The string has been saved.'), t('The string has been saved.'));
@@ -367,7 +367,7 @@ class LocaleTranslationFunctionalTest extends DrupalWebTestCase {
$query->addExpression('min(l.lid)', 'lid');
$result = $query->condition('l.location', '%.js%', 'LIKE')->execute();
$url = 'admin/config/regional/translate/edit/' . $result->fetchObject()->lid;
- $edit = array('translations['. $langcode .']' => $this->randomName());
+ $edit = array('translations['. $langcode .'][0]' => $this->randomName());
$this->drupalPost($url, $edit, t('Save translations'));
// Trigger JavaScript translation parsing and building.
@@ -434,7 +434,7 @@ class LocaleTranslationFunctionalTest extends DrupalWebTestCase {
$path = $matches[0];
foreach ($bad_translations as $key => $translation) {
$edit = array(
- "translations[$langcode]" => $translation,
+ "translations[$langcode][0]" => $translation,
);
$this->drupalPost($path, $edit, t('Save translations'));
// Check for a form error on the textarea.
@@ -521,7 +521,7 @@ class LocaleTranslationFunctionalTest extends DrupalWebTestCase {
preg_match('!admin/config/regional/translate/edit/(\d)+!', $this->getUrl(), $matches);
$lid = $matches[1];
$edit = array(
- "translations[$langcode]" => $translation,
+ "translations[$langcode][0]" => $translation,
);
$this->drupalPost(NULL, $edit, t('Save translations'));
@@ -586,26 +586,26 @@ class LocaleTranslationFunctionalTest extends DrupalWebTestCase {
}
/**
- * Tests plural index computation functionality.
+ * Tests plural format handling functionality.
*/
class LocalePluralFormatTest extends DrupalWebTestCase {
public static function getInfo() {
return array(
- 'name' => 'Plural formula evaluation',
- 'description' => 'Tests plural formula evaluation for various languages.',
+ 'name' => 'Plural handling',
+ 'description' => 'Tests plural handling for various languages.',
'group' => 'Locale',
);
}
function setUp() {
- parent::setUp('locale', 'locale_test');
+ parent::setUp('locale');
$admin_user = $this->drupalCreateUser(array('administer languages', 'translate interface', 'access administration pages'));
$this->drupalLogin($admin_user);
}
/**
- * Tests locale_get_plural() functionality.
+ * Tests locale_get_plural() and format_plural() functionality.
*/
function testGetPluralFormat() {
// Import some .po files with formulas to set up the environment.
@@ -629,30 +629,174 @@ class LocalePluralFormatTest extends DrupalWebTestCase {
// Reset static caches from locale_get_plural() to ensure we get fresh data.
drupal_static_reset('locale_get_plural');
drupal_static_reset('locale_get_plural:plurals');
+ drupal_static_reset('locale');
+
+ // Expected plural translation strings for each plural index.
+ $plural_strings = array(
+ // English is not imported in this case, so we assume built-in text
+ // and formulas.
+ 'en' => array(
+ 0 => '1 hour',
+ 1 => '@count hours',
+ ),
+ 'fr' => array(
+ 0 => '1 heure',
+ 1 => '@count heures',
+ ),
+ 'hr' => array(
+ 0 => '@count sat',
+ 1 => '@count sata',
+ 2 => '@count sati',
+ ),
+ // Hungarian is not imported, so it should assume the same text as
+ // English, but it will always pick the plural form as per the built-in
+ // logic, so only index -1 is relevant with the plural value.
+ 'hu' => array(
+ 0 => '1 hour',
+ -1 => '@count hours',
+ ),
+ );
+
+ // Expected plural indexes precomputed base on the plural formulas with
+ // given $count value.
+ $plural_tests = array(
+ 'en' => array(
+ 1 => 0,
+ 0 => 1,
+ 5 => 1,
+ ),
+ 'fr' => array(
+ 1 => 0,
+ 0 => 0,
+ 5 => 1,
+ ),
+ 'hr' => array(
+ 1 => 0,
+ 21 => 0,
+ 0 => 2,
+ 2 => 1,
+ 8 => 2,
+ ),
+ 'hu' => array(
+ 1 => -1,
+ 21 => -1,
+ 0 => -1,
+ ),
+ );
- // Test locale_get_plural() for English (no formula presnt).
- $this->assertIdentical(locale_get_plural(1, 'en'), 0, t("Computed plural index for 'en' with count 1 is 0."));
- $this->assertIdentical(locale_get_plural(0, 'en'), 1, t("Computed plural index for 'en' with count 0 is 1."));
- $this->assertIdentical(locale_get_plural(5, 'en'), 1, t("Computed plural index for 'en' with count 5 is 1."));
+ foreach ($plural_tests as $langcode => $tests) {
+ foreach ($tests as $count => $expected_plural_index) {
+ // Assert that the we get the right plural index.
+ $this->assertIdentical(locale_get_plural($count, $langcode), $expected_plural_index, 'Computed plural index for ' . $langcode . ' for count ' . $count . ' is ' . $expected_plural_index);
+ // Assert that the we get the right translation for that. Change the
+ // expected index as per the logic for translation lookups.
+ $expected_plural_index = ($count == 1) ? 0 : $expected_plural_index;
+ $expected_plural_string = str_replace('@count', $count, $plural_strings[$langcode][$expected_plural_index]);
+ $this->assertIdentical(format_plural($count, '1 hour', '@count hours', array(), array('langcode' => $langcode)), $expected_plural_string, 'Plural translation of 1 hours / @count hours for count ' . $count . ' in ' . $langcode . ' is ' . $expected_plural_string);
+ }
+ }
+ }
- // Test locale_get_plural() for French (simpler formula).
- $this->assertIdentical(locale_get_plural(1, 'fr'), 0, t("Computed plural index for 'fr' with count 1 is 0."));
- $this->assertIdentical(locale_get_plural(0, 'fr'), 0, t("Computed plural index for 'fr' with count 0 is 0."));
- $this->assertIdentical(locale_get_plural(5, 'fr'), 1, t("Computed plural index for 'fr' with count 5 is 1."));
+ /**
+ * Tests plural editing and export functionality.
+ */
+ function testPluralEditExport() {
+ // Import some .po files with formulas to set up the environment.
+ // These will also add the languages to the system and enable them.
+ $this->importPoFile($this->getPoFileWithSimplePlural(), array(
+ 'langcode' => 'fr',
+ ));
+ $this->importPoFile($this->getPoFileWithComplexPlural(), array(
+ 'langcode' => 'hr',
+ ));
- // Test locale_get_plural() for Croatian (more complex formula).
- $this->assertIdentical(locale_get_plural( 1, 'hr'), 0, t("Computed plural index for 'hr' with count 1 is 0."));
- $this->assertIdentical(locale_get_plural(21, 'hr'), 0, t("Computed plural index for 'hr' with count 21 is 0."));
- $this->assertIdentical(locale_get_plural( 0, 'hr'), 2, t("Computed plural index for 'hr' with count 0 is 2."));
- $this->assertIdentical(locale_get_plural( 2, 'hr'), 1, t("Computed plural index for 'hr' with count 2 is 1."));
- $this->assertIdentical(locale_get_plural( 8, 'hr'), 2, t("Computed plural index for 'hr' with count 8 is 2."));
+ // Get the French translations.
+ $this->drupalPost('admin/config/regional/translate/export', array(
+ 'langcode' => 'fr',
+ ), t('Export'));
+ // Ensure we have a translation file.
+ $this->assertRaw('# French translation of Drupal', t('Exported French translation file.'));
+ // Ensure our imported translations exist in the file.
+ $this->assertRaw("msgid \"Monday\"\nmsgstr \"lundi\"", t('French translations present in exported file.'));
+ // Check for plural export specifically.
+ $this->assertRaw("msgid \"1 hour\"\nmsgid_plural \"@count hours\"\nmsgstr[0] \"1 heure\"\nmsgstr[1] \"@count heures\"", t('Plural translations exported properly.'));
- // Test locale_get_plural() for Hungarian (nonexistent language).
- $this->assertIdentical(locale_get_plural( 1, 'hu'), -1, t("Computed plural index for 'hu' with count 1 is -1."));
- $this->assertIdentical(locale_get_plural(21, 'hu'), -1, t("Computed plural index for 'hu' with count 21 is -1."));
- $this->assertIdentical(locale_get_plural( 0, 'hu'), -1, t("Computed plural index for 'hu' with count 0 is -1."));
+ // Get the Croatian translations.
+ $this->drupalPost('admin/config/regional/translate/export', array(
+ 'langcode' => 'hr',
+ ), t('Export'));
+ // Ensure we have a translation file.
+ $this->assertRaw('# Croatian translation of Drupal', t('Exported Croatian translation file.'));
+ // Ensure our imported translations exist in the file.
+ $this->assertRaw("msgid \"Monday\"\nmsgstr \"Ponedjeljak\"", t('Croatian translations present in exported file.'));
+ // Check for plural export specifically.
+ $this->assertRaw("msgid \"1 hour\"\nmsgid_plural \"@count hours\"\nmsgstr[0] \"@count sat\"\nmsgstr[1] \"@count sata\"\nmsgstr[2] \"@count sati\"", t('Plural translations exported properly.'));
+
+ // Check if the source appears on the translation page.
+ $this->drupalGet('admin/config/regional/translate');
+ $this->assertText("1 hour, @count hours");
+
+ // Look up editing page for this plural string and check fields.
+ $lid = db_query("SELECT lid FROM {locales_source} WHERE source = :source AND context = ''", array(':source' => "1 hour" . LOCALE_PLURAL_DELIMITER . "@count hours"))->fetchField();
+ $path = 'admin/config/regional/translate/edit/' . $lid;
+ $this->drupalGet($path);
+ // Labels for plural editing elements.
+ $this->assertText('Singular form');
+ $this->assertText('First plural form');
+ $this->assertText('2. plural form');
+ // Plural values for both languages.
+ $this->assertFieldById('edit-translations-hr-0', '@count sat');
+ $this->assertFieldById('edit-translations-hr-1', '@count sata');
+ $this->assertFieldById('edit-translations-hr-2', '@count sati');
+ $this->assertNoFieldById('edit-translations-hr-3');
+ $this->assertFieldById('edit-translations-fr-0', '1 heure');
+ $this->assertFieldById('edit-translations-fr-1', '@count heures');
+ $this->assertNoFieldById('edit-translations-fr-2');
+
+ // Edit some translations and see if that took effect.
+ $edit = array(
+ 'translations[fr][0]' => '1 heure edited',
+ 'translations[hr][1]' => '@count sata edited',
+ );
+ $this->drupalPost($path, $edit, t('Save translations'));
+
+ // Inject a plural source string to the database. We need to use a specific
+ // langcode here because the language will be English by default and will
+ // not save our source string for performance optimization if we do not ask
+ // specifically for a language.
+ format_plural(1, '1 day', '@count days', array(), array('langcode' => 'fr'));
+ // Look up editing page for this plural string and check fields.
+ $lid = db_query("SELECT lid FROM {locales_source} WHERE source = :source AND context = ''", array(':source' => "1 day" . LOCALE_PLURAL_DELIMITER . "@count days"))->fetchField();
+ $path = 'admin/config/regional/translate/edit/' . $lid;
+
+ // Save complete translations for the string in both languages.
+ $edit = array(
+ 'translations[fr][0]' => '1 jour',
+ 'translations[fr][1]' => '@count jours',
+ 'translations[hr][0]' => '@count dan',
+ 'translations[hr][1]' => '@count dana',
+ 'translations[hr][2]' => '@count dana',
+ );
+ $this->drupalPost($path, $edit, t('Save translations'));
+
+ // Get the French translations.
+ $this->drupalPost('admin/config/regional/translate/export', array(
+ 'langcode' => 'fr',
+ ), t('Export'));
+ // Check for plural export specifically.
+ $this->assertRaw("msgid \"1 hour\"\nmsgid_plural \"@count hours\"\nmsgstr[0] \"1 heure edited\"\nmsgstr[1] \"@count heures\"", t('Edited French plural translations for hours exported properly.'));
+ $this->assertRaw("msgid \"1 day\"\nmsgid_plural \"@count days\"\nmsgstr[0] \"1 jour\"\nmsgstr[1] \"@count jours\"", t('Added French plural translations for days exported properly.'));
+
+ // Get the Croatian translations.
+ $this->drupalPost('admin/config/regional/translate/export', array(
+ 'langcode' => 'hr',
+ ), t('Export'));
+ // Check for plural export specifically.
+ $this->assertRaw("msgid \"1 hour\"\nmsgid_plural \"@count hours\"\nmsgstr[0] \"@count sat\"\nmsgstr[1] \"@count sata edited\"\nmsgstr[2] \"@count sati\"", t('Edited Croatian plural translations exported properly.'));
+ $this->assertRaw("msgid \"1 day\"\nmsgid_plural \"@count days\"\nmsgstr[0] \"@count dan\"\nmsgstr[1] \"@count dana\"\nmsgstr[2] \"@count dana\"", t('Added Croatian plural translations exported properly.'));
}
+
/**
* Imports a standalone .po file in a given language.
*
@@ -771,7 +915,7 @@ class LocaleImportFunctionalTest extends DrupalWebTestCase {
protected $admin_user = NULL;
function setUp() {
- parent::setUp('locale', 'locale_test');
+ parent::setUp(array('locale', 'locale_test', 'dblog'));
// Set the translation file directory.
variable_set('locale_translate_file_directory', drupal_get_path('module', 'locale_test'));
@@ -792,8 +936,8 @@ class LocaleImportFunctionalTest extends DrupalWebTestCase {
// The import should automatically create the corresponding language.
$this->assertRaw(t('The language %language has been created.', array('%language' => 'French')), t('The language has been automatically created.'));
- // The import should have created 7 strings.
- $this->assertRaw(t('The translation was successfully imported. There are %number newly created translated strings, %update strings were updated and %delete strings were removed.', array('%number' => 9, '%update' => 0, '%delete' => 0)), t('The translation file was successfully imported.'));
+ // The import should have created 8 strings.
+ $this->assertRaw(t('The translation was successfully imported. There are %number newly created translated strings, %update strings were updated and %delete strings were removed.', array('%number' => 8, '%update' => 0, '%delete' => 0)), t('The translation file was successfully imported.'));
// This import should have saved plural forms to have 2 variants.
$locale_plurals = variable_get('locale_translation_plurals', array());
@@ -1247,8 +1391,11 @@ class LocaleUninstallFunctionalTest extends DrupalWebTestCase {
protected $language;
function setUp() {
- parent::setUp('locale');
+ parent::setUp(array('node', 'locale'));
$this->langcode = 'en';
+
+ // Create Article node type.
+ $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
}
/**
@@ -1284,7 +1431,7 @@ class LocaleUninstallFunctionalTest extends DrupalWebTestCase {
$string = db_query('SELECT min(lid) AS lid FROM {locales_source} WHERE location LIKE :location', array(
':location' => '%.js%',
))->fetchObject();
- $edit = array('translations[fr]' => 'french translation');
+ $edit = array('translations[fr][0]' => 'french translation');
$this->drupalPost('admin/config/regional/translate/edit/' . $string->lid, $edit, t('Save translations'));
_locale_rebuild_js('fr');
$locale_javascripts = variable_get('locale_translation_javascript', array());
@@ -1301,7 +1448,7 @@ class LocaleUninstallFunctionalTest extends DrupalWebTestCase {
variable_set('language_negotiation_' . LANGUAGE_TYPE_CONTENT, locale_language_negotiation_info());
variable_set('language_negotiation_' . LANGUAGE_TYPE_URL, locale_language_negotiation_info());
- // Change language providers settings.
+ // Change language negotiation settings.
variable_set('locale_language_negotiation_url_part', LANGUAGE_NEGOTIATION_URL_PREFIX);
variable_set('locale_language_negotiation_session_param', TRUE);
@@ -1326,16 +1473,16 @@ class LocaleUninstallFunctionalTest extends DrupalWebTestCase {
// Check language negotiation.
require_once DRUPAL_ROOT . '/core/includes/language.inc';
$this->assertTrue(count(language_types_get_all()) == count(language_types_get_default()), t('Language types reset'));
- $language_negotiation = language_negotiation_get(LANGUAGE_TYPE_INTERFACE) == LANGUAGE_NEGOTIATION_DEFAULT;
+ $language_negotiation = language_negotiation_method_get_first(LANGUAGE_TYPE_INTERFACE) == LANGUAGE_NEGOTIATION_DEFAULT;
$this->assertTrue($language_negotiation, t('Interface language negotiation: %setting', array('%setting' => t($language_negotiation ? 'none' : 'set'))));
- $language_negotiation = language_negotiation_get(LANGUAGE_TYPE_CONTENT) == LANGUAGE_NEGOTIATION_DEFAULT;
+ $language_negotiation = language_negotiation_method_get_first(LANGUAGE_TYPE_CONTENT) == LANGUAGE_NEGOTIATION_DEFAULT;
$this->assertTrue($language_negotiation, t('Content language negotiation: %setting', array('%setting' => t($language_negotiation ? 'none' : 'set'))));
- $language_negotiation = language_negotiation_get(LANGUAGE_TYPE_URL) == LANGUAGE_NEGOTIATION_DEFAULT;
+ $language_negotiation = language_negotiation_method_get_first(LANGUAGE_TYPE_URL) == LANGUAGE_NEGOTIATION_DEFAULT;
$this->assertTrue($language_negotiation, t('URL language negotiation: %setting', array('%setting' => t($language_negotiation ? 'none' : 'set'))));
- // Check language providers settings.
- $this->assertFalse(variable_get('locale_language_negotiation_url_part', FALSE), t('URL language provider indicator settings cleared.'));
- $this->assertFalse(variable_get('locale_language_negotiation_session_param', FALSE), t('Visit language provider settings cleared.'));
+ // Check language negotiation method settings.
+ $this->assertFalse(variable_get('locale_language_negotiation_url_part', FALSE), t('URL language negotiation method indicator settings cleared.'));
+ $this->assertFalse(variable_get('locale_language_negotiation_session_param', FALSE), t('Visit language negotiation method settings cleared.'));
// Check JavaScript parsed.
$javascript_parsed_count = count(variable_get('javascript_parsed', array()));
@@ -1389,7 +1536,7 @@ class LocaleLanguageSwitchingFunctionalTest extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('locale');
+ parent::setUp(array('locale', 'block'));
// Create and login user.
$admin_user = $this->drupalCreateUser(array('administer blocks', 'administer languages', 'translate interface', 'access administration pages'));
@@ -1644,13 +1791,13 @@ class LocaleUserLanguageFunctionalTest extends DrupalWebTestCase {
$this->assertNoText($name_disabled, t('Disabled language not present on form.'));
// Switch to our custom language.
$edit = array(
- 'language' => $langcode,
+ 'preferred_langcode' => $langcode,
);
$this->drupalPost($path, $edit, t('Save'));
// Ensure form was submitted successfully.
$this->assertText(t('The changes have been saved.'), t('Changes were saved.'));
// Check if language was changed.
- $elements = $this->xpath('//input[@id=:id]', array(':id' => 'edit-language-' . $langcode));
+ $elements = $this->xpath('//input[@id=:id]', array(':id' => 'edit-preferred-langcode-' . $langcode));
$this->assertTrue(isset($elements[0]) && !empty($elements[0]['checked']), t('Default language successfully updated.'));
$this->drupalLogout();
@@ -1689,7 +1836,7 @@ class LocaleUserCreationTest extends DrupalWebTestCase {
'predefined_langcode' => 'fr',
);
$this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
- $this->assertText($langcode, t('Language added successfully.'));
+ $this->assertText('French', t('Language added successfully.'));
$this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
// Set language negotiation.
@@ -1702,7 +1849,7 @@ class LocaleUserCreationTest extends DrupalWebTestCase {
// Check if the language selector is available on admin/people/create and
// set to the currently active language.
$this->drupalGet($langcode . '/admin/people/create');
- $this->assertFieldChecked("edit-language-$langcode", t('Global language set in the language selector.'));
+ $this->assertFieldChecked("edit-preferred-langcode-$langcode", t('Global language set in the language selector.'));
// Create a user with the admin/people/create form and check if the correct
// language is set.
@@ -1717,7 +1864,8 @@ class LocaleUserCreationTest extends DrupalWebTestCase {
$this->drupalPost($langcode . '/admin/people/create', $edit, t('Create new account'));
$user = user_load_by_name($username);
- $this->assertEqual($user->language, $langcode, t('New user has correct language set.'));
+ $this->assertEqual($user->preferred_langcode, $langcode, t('New user has correct preferred language set.'));
+ $this->assertEqual($user->langcode, $langcode, t('New user has correct profile language set.'));
// Register a new user and check if the language selector is hidden.
$this->drupalLogout();
@@ -1734,7 +1882,8 @@ class LocaleUserCreationTest extends DrupalWebTestCase {
$this->drupalPost($langcode . '/user/register', $edit, t('Create new account'));
$user = user_load_by_name($username);
- $this->assertEqual($user->language, $langcode, t('New user has correct language set.'));
+ $this->assertEqual($user->preferred_langcode, $langcode, t('New user has correct preferred language set.'));
+ $this->assertEqual($user->langcode, $langcode, t('New user has correct profile language set.'));
// Test if the admin can use the language selector and if the
// correct language is was saved.
@@ -1742,7 +1891,7 @@ class LocaleUserCreationTest extends DrupalWebTestCase {
$this->drupalLogin($admin_user);
$this->drupalGet($user_edit);
- $this->assertFieldChecked("edit-language-$langcode", t('Language selector is accessible and correct language is selected.'));
+ $this->assertFieldChecked("edit-preferred-langcode-$langcode", t('Language selector is accessible and correct language is selected.'));
// Set pass_raw so we can login the new user.
$user->pass_raw = $this->randomName(10);
@@ -1755,7 +1904,7 @@ class LocaleUserCreationTest extends DrupalWebTestCase {
$this->drupalLogin($user);
$this->drupalGet($user_edit);
- $this->assertFieldChecked("edit-language-$langcode", t('Language selector is accessible and correct language is selected.'));
+ $this->assertFieldChecked("edit-preferred-langcode-$langcode", t('Language selector is accessible and correct language is selected.'));
}
}
@@ -1772,7 +1921,10 @@ class LocalePathFunctionalTest extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('locale', 'path');
+ parent::setUp(array('node', 'locale', 'path'));
+
+ $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
+ variable_set('site_frontpage', 'node');
}
/**
@@ -1846,7 +1998,7 @@ class LocalePathFunctionalTest extends DrupalWebTestCase {
$edit = array(
'source' => 'node/' . $node->nid,
'alias' => $custom_path,
- 'langcode' => LANGUAGE_NONE,
+ 'langcode' => LANGUAGE_NOT_SPECIFIED,
);
path_save($edit);
$lookup_path = drupal_lookup_path('alias', 'node/' . $node->nid, 'en');
@@ -1857,8 +2009,8 @@ class LocalePathFunctionalTest extends DrupalWebTestCase {
path_delete($edit);
// Create language nodes to check priority of aliases.
- $first_node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1));
- $second_node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1));
+ $first_node = $this->drupalCreateNode(array('type' => 'page', 'promote' => 1));
+ $second_node = $this->drupalCreateNode(array('type' => 'page', 'promote' => 1));
// Assign a custom path alias to the first node with the English language.
$edit = array(
@@ -1868,11 +2020,11 @@ class LocalePathFunctionalTest extends DrupalWebTestCase {
);
path_save($edit);
- // Assign a custom path alias to second node with LANGUAGE_NONE.
+ // Assign a custom path alias to second node with LANGUAGE_NOT_SPECIFIED.
$edit = array(
'source' => 'node/' . $second_node->nid,
'alias' => $custom_path,
- 'langcode' => LANGUAGE_NONE,
+ 'langcode' => LANGUAGE_NOT_SPECIFIED,
);
path_save($edit);
@@ -1899,6 +2051,8 @@ class LocalePathFunctionalTest extends DrupalWebTestCase {
* Functional tests for multilingual support on nodes.
*/
class LocaleContentFunctionalTest extends DrupalWebTestCase {
+ protected $profile = 'standard';
+
public static function getInfo() {
return array(
'name' => 'Content language settings',
@@ -2150,7 +2304,7 @@ class LocaleUILanguageNegotiationTest extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('locale', 'locale_test');
+ parent::setUp(array('locale', 'locale_test', 'block'));
require_once DRUPAL_ROOT . '/core/includes/language.inc';
drupal_load('module', 'locale');
$admin_user = $this->drupalCreateUser(array('administer languages', 'translate interface', 'access administration pages', 'administer blocks'));
@@ -2212,8 +2366,8 @@ class LocaleUILanguageNegotiationTest extends DrupalWebTestCase {
// Should find the string and now click edit to post translated string.
$this->clickLink('edit');
$edit = array(
- "translations[$langcode_browser_fallback]" => $language_browser_fallback_string,
- "translations[$langcode]" => $language_string,
+ "translations[$langcode_browser_fallback][0]" => $language_browser_fallback_string,
+ "translations[$langcode][0]" => $language_string,
);
$this->drupalPost(NULL, $edit, t('Save translations'));
@@ -2226,7 +2380,7 @@ class LocaleUILanguageNegotiationTest extends DrupalWebTestCase {
'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_DEFAULT),
'path' => 'admin/config',
'expect' => $default_string,
- 'expected_provider' => LANGUAGE_NEGOTIATION_DEFAULT,
+ 'expected_method_id' => LANGUAGE_NEGOTIATION_DEFAULT,
'http_header' => $http_header_browser_fallback,
'message' => 'URL (PATH) > DEFAULT: no language prefix, UI language is default and the browser language preference setting is not used.',
),
@@ -2235,7 +2389,7 @@ class LocaleUILanguageNegotiationTest extends DrupalWebTestCase {
'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_DEFAULT),
'path' => "$langcode/admin/config",
'expect' => $language_string,
- 'expected_provider' => LANGUAGE_NEGOTIATION_URL,
+ 'expected_method_id' => LANGUAGE_NEGOTIATION_URL,
'http_header' => $http_header_browser_fallback,
'message' => 'URL (PATH) > DEFAULT: with language prefix, UI language is switched based on path prefix',
),
@@ -2244,7 +2398,7 @@ class LocaleUILanguageNegotiationTest extends DrupalWebTestCase {
'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_BROWSER),
'path' => 'admin/config',
'expect' => $language_browser_fallback_string,
- 'expected_provider' => LANGUAGE_NEGOTIATION_BROWSER,
+ 'expected_method_id' => LANGUAGE_NEGOTIATION_BROWSER,
'http_header' => $http_header_browser_fallback,
'message' => 'URL (PATH) > BROWSER: no language prefix, UI language is determined by browser language preference',
),
@@ -2253,7 +2407,7 @@ class LocaleUILanguageNegotiationTest extends DrupalWebTestCase {
'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_BROWSER),
'path' => "$langcode/admin/config",
'expect' => $language_string,
- 'expected_provider' => LANGUAGE_NEGOTIATION_URL,
+ 'expected_method_id' => LANGUAGE_NEGOTIATION_URL,
'http_header' => $http_header_browser_fallback,
'message' => 'URL (PATH) > BROWSER: with langage prefix, UI language is based on path prefix',
),
@@ -2262,7 +2416,7 @@ class LocaleUILanguageNegotiationTest extends DrupalWebTestCase {
'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_BROWSER, LANGUAGE_NEGOTIATION_DEFAULT),
'path' => 'admin/config',
'expect' => $default_string,
- 'expected_provider' => LANGUAGE_NEGOTIATION_DEFAULT,
+ 'expected_method_id' => LANGUAGE_NEGOTIATION_DEFAULT,
'http_header' => $http_header_blah,
'message' => 'URL (PATH) > BROWSER > DEFAULT: no language prefix and browser language preference set to unknown language should use default language',
),
@@ -2278,8 +2432,8 @@ class LocaleUILanguageNegotiationTest extends DrupalWebTestCase {
$this->assertResponse(404, "Unknown language path prefix should return 404");
// Setup for domain negotiation, first configure the language to have domain
- // URL. We use https and a port to make sure that only the domain name is used.
- $edit = array("domain[$langcode]" => "https://$language_domain:99");
+ // URL.
+ $edit = array("domain[$langcode]" => $language_domain);
$this->drupalPost("admin/config/regional/language/detection/url", $edit, t('Save configuration'));
// Set the site to use domain language negotiation.
@@ -2290,7 +2444,7 @@ class LocaleUILanguageNegotiationTest extends DrupalWebTestCase {
'locale_language_negotiation_url_part' => LANGUAGE_NEGOTIATION_URL_DOMAIN,
'path' => 'admin/config',
'expect' => $default_string,
- 'expected_provider' => LANGUAGE_NEGOTIATION_DEFAULT,
+ 'expected_method_id' => LANGUAGE_NEGOTIATION_DEFAULT,
'http_header' => $http_header_browser_fallback,
'message' => 'URL (DOMAIN) > DEFAULT: default domain should get default language',
),
@@ -2302,7 +2456,7 @@ class LocaleUILanguageNegotiationTest extends DrupalWebTestCase {
'locale_test_domain' => $language_domain,
'path' => 'admin/config',
'expect' => $language_string,
- 'expected_provider' => LANGUAGE_NEGOTIATION_URL,
+ 'expected_method_id' => LANGUAGE_NEGOTIATION_URL,
'http_header' => $http_header_browser_fallback,
'message' => 'URL (DOMAIN) > DEFAULT: domain example.cn should switch to Chinese',
),
@@ -2315,8 +2469,8 @@ class LocaleUILanguageNegotiationTest extends DrupalWebTestCase {
protected function runTest($test) {
if (!empty($test['language_negotiation'])) {
- $negotiation = array_flip($test['language_negotiation']);
- language_negotiation_set(LANGUAGE_TYPE_INTERFACE, $negotiation);
+ $method_weights = array_flip($test['language_negotiation']);
+ language_negotiation_set(LANGUAGE_TYPE_INTERFACE, $method_weights);
}
if (!empty($test['locale_language_negotiation_url_part'])) {
variable_set('locale_language_negotiation_url_part', $test['locale_language_negotiation_url_part']);
@@ -2326,7 +2480,7 @@ class LocaleUILanguageNegotiationTest extends DrupalWebTestCase {
}
$this->drupalGet($test['path'], array(), $test['http_header']);
$this->assertText($test['expect'], $test['message']);
- $this->assertText(t('Language negotiation provider: @name', array('@name' => $test['expected_provider'])));
+ $this->assertText(t('Language negotiation method: @name', array('@name' => $test['expected_method_id'])));
}
/**
@@ -2369,11 +2523,11 @@ class LocaleUILanguageNegotiationTest extends DrupalWebTestCase {
// Check that the language switcher active link matches the given browser
// language.
$args = array(':url' => base_path() . (!empty($GLOBALS['conf']['clean_url']) ? $langcode_browser_fallback : "?q=$langcode_browser_fallback"));
- $fields = $this->xpath('//div[@id="block-locale-language-interface"]//a[@class="language-link active" and @href=:url]', $args);
+ $fields = $this->xpath('//div[@id="block-locale-language-interface"]//a[@class="language-link active" and starts-with(@href, :url)]', $args);
$this->assertTrue($fields[0] == $languages[$langcode_browser_fallback]->name, t('The browser language is the URL active language'));
// Check that URLs are rewritten using the given browser language.
- $fields = $this->xpath('//div[@id="site-name"]//a[@rel="home" and @href=:url]//span', $args);
+ $fields = $this->xpath('//p[@id="site-name"]/strong/a[@rel="home" and @href=:url]', $args);
$this->assertTrue($fields[0] == 'Drupal', t('URLs are rewritten using the browser language.'));
}
@@ -2530,7 +2684,11 @@ class LocaleMultilingualFieldsFunctionalTest extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('locale');
+ parent::setUp(array('node', 'locale'));
+
+ // Create Basic page node type.
+ $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
+
// Setup users.
$admin_user = $this->drupalCreateUser(array('administer languages', 'administer content types', 'access administration pages', 'create page content', 'edit own page content'));
$this->drupalLogin($admin_user);
@@ -2565,7 +2723,7 @@ class LocaleMultilingualFieldsFunctionalTest extends DrupalWebTestCase {
*/
function testMultilingualNodeForm() {
// Create "Basic page" content.
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$title_key = "title";
$title_value = $this->randomName(8);
$body_key = "body[$langcode][0][value]";
@@ -2582,7 +2740,7 @@ class LocaleMultilingualFieldsFunctionalTest extends DrupalWebTestCase {
$node = $this->drupalGetNodeByTitle($edit[$title_key]);
$this->assertTrue($node, t('Node found in database.'));
- $assert = isset($node->body['en']) && !isset($node->body[LANGUAGE_NONE]) && $node->body['en'][0]['value'] == $body_value;
+ $assert = isset($node->body['en']) && !isset($node->body[LANGUAGE_NOT_SPECIFIED]) && $node->body['en'][0]['value'] == $body_value;
$this->assertTrue($assert, t('Field language correctly set.'));
// Change node language.
@@ -2614,7 +2772,7 @@ class LocaleMultilingualFieldsFunctionalTest extends DrupalWebTestCase {
*/
function testMultilingualDisplaySettings() {
// Create "Basic page" content.
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$title_key = "title";
$title_value = $this->randomName(8);
$body_key = "body[$langcode][0][value]";
@@ -2633,8 +2791,11 @@ class LocaleMultilingualFieldsFunctionalTest extends DrupalWebTestCase {
// Check if node body is showed.
$this->drupalGet("node/$node->nid");
- $body = $this->xpath('//div[@id=:id]//div[@property="content:encoded"]/p', array(':id' => 'node-' . $node->nid));
- $this->assertEqual(current($body), $node->body['en'][0]['value'], 'Node body is correctly showed.');
+ $body = $this->xpath('//article[@id=:id]//div[@class=:class]/descendant::p', array(
+ ':id' => 'node-' . $node->nid,
+ ':class' => 'content',
+ ));
+ $this->assertEqual(current($body), $node->body['en'][0]['value'], 'Node body found.');
}
}
@@ -2642,6 +2803,7 @@ class LocaleMultilingualFieldsFunctionalTest extends DrupalWebTestCase {
* Functional tests for comment language.
*/
class LocaleCommentLanguageFunctionalTest extends DrupalWebTestCase {
+ protected $profile = 'standard';
public static function getInfo() {
return array(
@@ -2682,7 +2844,7 @@ class LocaleCommentLanguageFunctionalTest extends DrupalWebTestCase {
// Change user language preference, this way interface language is always
// French no matter what path prefix the URLs have.
- $edit = array('language' => 'fr');
+ $edit = array('preferred_langcode' => 'fr');
$this->drupalPost("user/{$admin_user->uid}/edit", $edit, t('Save'));
}
@@ -2699,13 +2861,13 @@ class LocaleCommentLanguageFunctionalTest extends DrupalWebTestCase {
// language and interface language do not influence comment language, as
// only content language has to.
foreach (language_list() as $node_langcode => $node_language) {
- $langcode_none = LANGUAGE_NONE;
+ $langcode_not_specified = LANGUAGE_NOT_SPECIFIED;
// Create "Article" content.
$title = $this->randomName();
$edit = array(
"title" => $title,
- "body[$langcode_none][0][value]" => $this->randomName(),
+ "body[$langcode_not_specified][0][value]" => $this->randomName(),
"langcode" => $node_langcode,
);
$this->drupalPost("node/add/article", $edit, t('Save'));
@@ -2715,7 +2877,7 @@ class LocaleCommentLanguageFunctionalTest extends DrupalWebTestCase {
foreach (language_list() as $langcode => $language) {
// Post a comment with content language $langcode.
$prefix = empty($prefixes[$langcode]) ? '' : $prefixes[$langcode] . '/';
- $edit = array("comment_body[$langcode_none][0][value]" => $this->randomName());
+ $edit = array("comment_body[$langcode_not_specified][0][value]" => $this->randomName());
$this->drupalPost("{$prefix}node/{$node->nid}", $edit, t('Save'));
// Check that comment language matches the current content language.
@@ -2746,7 +2908,10 @@ class LocaleDateFormatsFunctionalTest extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('locale');
+ parent::setUp(array('node', 'locale'));
+
+ // Create Article node type.
+ $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
// Create and login user.
$admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer languages', 'access administration pages', 'create article content'));
@@ -2843,36 +3008,36 @@ class LocaleLanguageNegotiationInfoFunctionalTest extends DrupalWebTestCase {
$language_types = variable_get('language_types', language_types_get_default());
$this->assertTrue($language_types[$type], t('Content language type is configurable.'));
- // Enable some core and custom language providers. The test language type is
- // supposed to be configurable.
+ // Enable some core and custom language negotiation methods. The test
+ // language type is supposed to be configurable.
$test_type = 'test_language_type';
- $provider = LANGUAGE_NEGOTIATION_INTERFACE;
- $test_provider = 'test_language_provider';
- $form_field = $type . '[enabled]['. $provider .']';
+ $interface_method_id = LANGUAGE_NEGOTIATION_INTERFACE;
+ $test_method_id = 'test_language_negotiation_method';
+ $form_field = $type . '[enabled]['. $interface_method_id .']';
$edit = array(
$form_field => TRUE,
- $type . '[enabled][' . $test_provider . ']' => TRUE,
- $test_type . '[enabled][' . $test_provider . ']' => TRUE,
+ $type . '[enabled][' . $test_method_id . ']' => TRUE,
+ $test_type . '[enabled][' . $test_method_id . ']' => TRUE,
);
$this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings'));
- // Remove the interface language provider by updating the language
+ // Remove the interface language negotiation method by updating the language
// negotiation settings with the proper flag enabled.
variable_set('locale_test_language_negotiation_info_alter', TRUE);
$this->languageNegotiationUpdate();
$negotiation = variable_get("language_negotiation_$type", array());
- $this->assertFalse(isset($negotiation[$provider]), t('Interface language provider removed from the stored settings.'));
- $this->assertNoFieldByXPath("//input[@name=\"$form_field\"]", NULL, t('Interface language provider unavailable.'));
+ $this->assertFalse(isset($negotiation[$interface_method_id]), t('Interface language negotiation method removed from the stored settings.'));
+ $this->assertNoFieldByXPath("//input[@name=\"$form_field\"]", NULL, t('Interface language negotiation method unavailable.'));
- // Check that type-specific language providers can be assigned only to the
- // corresponding language types.
+ // Check that type-specific language negotiation methods can be assigned
+ // only to the corresponding language types.
foreach (language_types_get_configurable() as $type) {
- $form_field = $type . '[enabled][test_language_provider_ts]';
+ $form_field = $type . '[enabled][test_language_negotiation_method_ts]';
if ($type == $test_type) {
- $this->assertFieldByXPath("//input[@name=\"$form_field\"]", NULL, t('Type-specific test language provider available for %type.', array('%type' => $type)));
+ $this->assertFieldByXPath("//input[@name=\"$form_field\"]", NULL, t('Type-specific test language negotiation method available for %type.', array('%type' => $type)));
}
else {
- $this->assertNoFieldByXPath("//input[@name=\"$form_field\"]", NULL, t('Type-specific test language provider unavailable for %type.', array('%type' => $type)));
+ $this->assertNoFieldByXPath("//input[@name=\"$form_field\"]", NULL, t('Type-specific test language negotiation method unavailable for %type.', array('%type' => $type)));
}
}
@@ -2898,14 +3063,14 @@ class LocaleLanguageNegotiationInfoFunctionalTest extends DrupalWebTestCase {
// previously set to configurable.
$this->checkFixedLanguageTypes();
- // Check that unavailable language providers are not present in the
- // negotiation settings.
+ // Check that unavailable language negotiation methods are not present in
+ // the negotiation settings.
$negotiation = variable_get("language_negotiation_$type", array());
- $this->assertFalse(isset($negotiation[$test_provider]), t('The disabled test language provider is not part of the content language negotiation settings.'));
+ $this->assertFalse(isset($negotiation[$test_method_id]), t('The disabled test language negotiation method is not part of the content language negotiation settings.'));
// Check that configuration page presents the correct options and settings.
$this->assertNoRaw(t('Test language detection'), t('No test language type configuration available.'));
- $this->assertNoRaw(t('This is a test language provider'), t('No test language provider available.'));
+ $this->assertNoRaw(t('This is a test language negotiation method'), t('No test language negotiation method available.'));
}
/**
diff --git a/core/modules/locale/tests/locale_test.module b/core/modules/locale/tests/locale_test.module
index a0bdf43..93dfaa1 100644
--- a/core/modules/locale/tests/locale_test.module
+++ b/core/modules/locale/tests/locale_test.module
@@ -22,8 +22,8 @@ function locale_test_boot() {
*/
function locale_test_init() {
locale_test_store_language_negotiation();
- if (isset($GLOBALS['language_interface']) && isset($GLOBALS['language_interface']->provider)) {
- drupal_set_message(t('Language negotiation provider: @name', array('@name' => $GLOBALS['language_interface']->provider)));
+ if (isset($GLOBALS['language_interface']) && isset($GLOBALS['language_interface']->method_id)) {
+ drupal_set_message(t('Language negotiation method: @name', array('@name' => $GLOBALS['language_interface']->method_id)));
}
}
@@ -38,7 +38,7 @@ function locale_test_language_types_info() {
'description' => t('A test language type.'),
),
'fixed_test_language_type' => array(
- 'fixed' => array('test_language_provider'),
+ 'fixed' => array('test_language_negotiation_method'),
),
);
}
@@ -60,19 +60,19 @@ function locale_test_language_negotiation_info() {
if (variable_get('locale_test_language_negotiation_info', FALSE)) {
$info = array(
'callbacks' => array(
- 'language' => 'locale_test_language_provider',
+ 'negotiation' => 'locale_test_language_negotiation_method',
),
'file' => drupal_get_path('module', 'locale_test') .'/locale_test.module',
'weight' => -10,
- 'description' => t('This is a test language provider.'),
+ 'description' => t('This is a test language negotiation method.'),
);
return array(
- 'test_language_provider' => array(
+ 'test_language_negotiation_method' => array(
'name' => t('Test'),
'types' => array(LANGUAGE_TYPE_CONTENT, 'test_language_type', 'fixed_test_language_type'),
) + $info,
- 'test_language_provider_ts' => array(
+ 'test_language_negotiation_method_ts' => array(
'name' => t('Type-specific test'),
'types' => array('test_language_type'),
) + $info,
@@ -83,9 +83,9 @@ function locale_test_language_negotiation_info() {
/**
* Implements hook_language_negotiation_info_alter().
*/
-function locale_test_language_negotiation_info_alter(array &$language_providers) {
+function locale_test_language_negotiation_info_alter(array &$negotiation_info) {
if (variable_get('locale_test_language_negotiation_info_alter', FALSE)) {
- unset($language_providers[LANGUAGE_NEGOTIATION_INTERFACE]);
+ unset($negotiation_info[LANGUAGE_NEGOTIATION_INTERFACE]);
}
}
@@ -101,8 +101,8 @@ function locale_test_store_language_negotiation() {
}
/**
- * Test language provider.
+ * Provides a test language negotiation method.
*/
-function locale_test_language_provider($languages) {
+function locale_test_language_negotiation_method($languages) {
return 'it';
}
diff --git a/core/modules/menu/menu.css b/core/modules/menu/menu.admin.css
similarity index 59%
rename from core/modules/menu/menu.css
rename to core/modules/menu/menu.admin.css
index 96f861a..8717aca 100644
--- a/core/modules/menu/menu.css
+++ b/core/modules/menu/menu.admin.css
@@ -1,12 +1,6 @@
-
.menu-operations {
width: 100px;
}
-
.menu-enabled {
width: 70px;
}
-
-.menu-enabled input {
- margin-left:25px;
-}
diff --git a/core/modules/menu/menu.admin.inc b/core/modules/menu/menu.admin.inc
index f933feb..354261d 100644
--- a/core/modules/menu/menu.admin.inc
+++ b/core/modules/menu/menu.admin.inc
@@ -48,7 +48,7 @@ function theme_menu_admin_overview($variables) {
*/
function menu_overview_form($form, &$form_state, $menu) {
global $menu_admin;
- $form['#attached']['css'] = array(drupal_get_path('module', 'menu') . '/menu.css');
+ $form['#attached']['css'] = array(drupal_get_path('module', 'menu') . '/menu.admin.css');
$sql = "
SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.delivery_callback, m.title, m.title_callback, m.title_arguments, m.type, m.description, ml.*
FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path
diff --git a/core/modules/menu/menu.test b/core/modules/menu/menu.test
index 0497a2a..e1f2aa9 100644
--- a/core/modules/menu/menu.test
+++ b/core/modules/menu/menu.test
@@ -6,6 +6,8 @@
*/
class MenuTestCase extends DrupalWebTestCase {
+ protected $profile = 'standard';
+
protected $big_user;
protected $std_user;
protected $menu;
@@ -582,6 +584,8 @@ class MenuTestCase extends DrupalWebTestCase {
* Test menu settings for nodes.
*/
class MenuNodeTestCase extends DrupalWebTestCase {
+ protected $profile = 'standard';
+
public static function getInfo() {
return array(
'name' => 'Menu settings for nodes',
@@ -622,10 +626,10 @@ class MenuNodeTestCase extends DrupalWebTestCase {
// Create a node.
$node_title = $this->randomName();
- $language = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$edit = array(
"title" => $node_title,
- "body[$language][0][value]" => $this->randomString(),
+ "body[$langcode][0][value]" => $this->randomString(),
);
$this->drupalPost('node/add/page', $edit, t('Save'));
$node = $this->drupalGetNodeByTitle($node_title);
diff --git a/core/modules/node/node.admin.inc b/core/modules/node/node.admin.inc
index 1a33174..e5d6a15 100644
--- a/core/modules/node/node.admin.inc
+++ b/core/modules/node/node.admin.inc
@@ -107,7 +107,7 @@ function node_filters() {
// Language filter if the site is multilingual.
if (language_multilingual()) {
$languages = language_list(TRUE);
- $language_options = array(LANGUAGE_NONE => t('- None -'));
+ $language_options = array(LANGUAGE_NOT_SPECIFIED => t('- None -'));
foreach ($languages as $langcode => $language) {
$language_options[$langcode] = $language->name;
}
@@ -433,7 +433,7 @@ function node_admin_nodes() {
// Enable language column if translation module is enabled or if we have any
// node with language.
- $multilanguage = (module_exists('translation') || db_query_range("SELECT 1 FROM {node} WHERE langcode <> :langcode", 0, 1, array(':langcode' => LANGUAGE_NONE))->fetchField());
+ $multilanguage = (module_exists('translation') || db_query_range("SELECT 1 FROM {node} WHERE langcode <> :langcode", 0, 1, array(':langcode' => LANGUAGE_NOT_SPECIFIED))->fetchField());
// Build the sortable table header.
$header = array(
@@ -479,7 +479,7 @@ function node_admin_nodes() {
$destination = drupal_get_destination();
$options = array();
foreach ($nodes as $node) {
- $l_options = $node->langcode != LANGUAGE_NONE && isset($languages[$node->langcode]) ? array('language' => $languages[$node->langcode]) : array();
+ $l_options = $node->langcode != LANGUAGE_NOT_SPECIFIED && isset($languages[$node->langcode]) ? array('language' => $languages[$node->langcode]) : array();
$options[$node->nid] = array(
'title' => array(
'data' => array(
diff --git a/core/modules/node/node.api.php b/core/modules/node/node.api.php
index 1c70b00..2324b47 100644
--- a/core/modules/node/node.api.php
+++ b/core/modules/node/node.api.php
@@ -383,7 +383,7 @@ function hook_node_grants_alter(&$grants, $account, $op) {
if ($op != 'view' && !empty($restricted)) {
// Now check the roles for this account against the restrictions.
foreach ($restricted as $role_id) {
- if (isset($user->roles[$role_id])) {
+ if (isset($account->roles[$role_id])) {
$grants = array();
}
}
@@ -718,8 +718,8 @@ function hook_node_update($node) {
* @param $node
* The node being indexed.
*
- * @return
- * Array of additional information to be indexed.
+ * @return string
+ * Additional node information to be indexed.
*
* @ingroup node_api_hooks
*/
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 399f543..3bc04cf 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -3403,9 +3403,6 @@ function _node_query_node_access_alter($query, $type) {
}
}
- // Prevent duplicate records.
- $query->distinct();
-
// Find all instances of the base table being joined -- could appear
// more than once in the query, and could be aliased. Join each one to
// the node_access table.
@@ -3434,17 +3431,9 @@ function _node_query_node_access_alter($query, $type) {
foreach ($tables as $nalias => $tableinfo) {
$table = $tableinfo['table'];
if (!($table instanceof SelectInterface) && $table == $base_table) {
-
- // The node_access table has the access grants for any given node so JOIN
- // it to the table containing the nid which can be either the node
- // table or a field value table.
- if ($type == 'node') {
- $access_alias = $query->join('node_access', 'na', '%alias.nid = ' . $nalias . '.nid');
- }
- else {
- $access_alias = $query->leftJoin('node_access', 'na', '%alias.nid = ' . $nalias . '.entity_id');
- $base_alias = $nalias;
- }
+ // Set the subquery.
+ $subquery = db_select('node_access', 'na')
+ ->fields('na', array('nid'));
$grant_conditions = db_or();
// If any grant exists for the specified user, then user has access
@@ -3452,29 +3441,30 @@ function _node_query_node_access_alter($query, $type) {
foreach ($grants as $realm => $gids) {
foreach ($gids as $gid) {
$grant_conditions->condition(db_and()
- ->condition($access_alias . '.gid', $gid)
- ->condition($access_alias . '.realm', $realm)
+ ->condition('na.gid', $gid)
+ ->condition('na.realm', $realm)
);
}
}
- $count = count($grant_conditions->conditions());
- if ($type == 'node') {
- if ($count) {
- $query->condition($grant_conditions);
- }
- $query->condition($access_alias . '.grant_' . $op, 1, '>=');
+ // Attach conditions to the subquery for nodes.
+ if (count($grant_conditions->conditions())) {
+ $subquery->condition($grant_conditions);
}
- else {
- if ($count) {
- $entity_conditions->condition($grant_conditions);
- }
- $entity_conditions->condition($access_alias . '.grant_' . $op, 1, '>=');
+ $subquery->condition('na.grant_' . $op, 1, '>=');
+ $field = 'nid';
+ // Now handle entities.
+ if ($type == 'entity') {
+ // Set a common alias for entities.
+ $base_alias = $nalias;
+ $field = 'entity_id';
}
+ $subquery->where("$nalias.$field = na.nid");
+ $query->exists($subquery);
}
}
- if ($type == 'entity' && count($entity_conditions->conditions())) {
+ if ($type == 'entity' && count($subquery->conditions())) {
// All the node access conditions are only for field values belonging to
// nodes.
$entity_conditions->condition("$base_alias.entity_type", 'node');
@@ -3486,6 +3476,7 @@ function _node_query_node_access_alter($query, $type) {
// Add the compiled set of rules to the query.
$query->condition($or);
}
+
}
/**
diff --git a/core/modules/node/node.pages.inc b/core/modules/node/node.pages.inc
index 34a8d4f..4e94b26 100644
--- a/core/modules/node/node.pages.inc
+++ b/core/modules/node/node.pages.inc
@@ -81,7 +81,7 @@ function node_add($type) {
global $user;
$types = node_type_get_types();
- $node = (object) array('uid' => $user->uid, 'name' => (isset($user->name) ? $user->name : ''), 'type' => $type, 'langcode' => LANGUAGE_NONE);
+ $node = (object) array('uid' => $user->uid, 'name' => (isset($user->name) ? $user->name : ''), 'type' => $type, 'langcode' => LANGUAGE_NOT_SPECIFIED);
drupal_set_title(t('Create @name', array('@name' => $types[$type]->name)), PASS_THROUGH);
$output = drupal_get_form($type . '_node_form', $node);
@@ -186,7 +186,7 @@ function node_form($form, &$form_state, $node) {
'#title' => t('Language'),
'#default_value' => (isset($node->langcode) ? $node->langcode : ''),
'#options' => $language_options,
- '#empty_value' => LANGUAGE_NONE,
+ '#empty_value' => LANGUAGE_NOT_SPECIFIED,
);
}
else {
diff --git a/core/modules/node/node.test b/core/modules/node/node.test
index b9cae4c..1dbcaf3 100644
--- a/core/modules/node/node.test
+++ b/core/modules/node/node.test
@@ -7,10 +7,27 @@ use Drupal\Core\Database\Database;
* Tests for node.module.
*/
+class NodeWebTestCase extends DrupalWebTestCase {
+ function setUp() {
+ $modules = func_get_args();
+ if (isset($modules[0]) && is_array($modules[0])) {
+ $modules = $modules[0];
+ }
+ $modules[] = 'node';
+ parent::setUp($modules);
+
+ // Create Basic page and Article node types.
+ if ($this->profile != 'standard') {
+ $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
+ $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
+ }
+ }
+}
+
/**
* Tests the node_load_multiple() function.
*/
-class NodeLoadMultipleUnitTest extends DrupalWebTestCase {
+class NodeLoadMultipleUnitTest extends NodeWebTestCase {
public static function getInfo() {
return array(
@@ -90,7 +107,7 @@ class NodeLoadMultipleUnitTest extends DrupalWebTestCase {
/**
* Tests for the hooks invoked during node_load().
*/
-class NodeLoadHooksTestCase extends DrupalWebTestCase {
+class NodeLoadHooksTestCase extends NodeWebTestCase {
public static function getInfo() {
return array(
'name' => 'Node load hooks',
@@ -131,7 +148,7 @@ class NodeLoadHooksTestCase extends DrupalWebTestCase {
}
}
-class NodeRevisionsTestCase extends DrupalWebTestCase {
+class NodeRevisionsTestCase extends NodeWebTestCase {
protected $nodes;
protected $logs;
@@ -191,7 +208,7 @@ class NodeRevisionsTestCase extends DrupalWebTestCase {
// Confirm the correct revision text appears on "view revisions" page.
$this->drupalGet("node/$node->nid/revisions/$node->vid/view");
- $this->assertText($node->body[LANGUAGE_NONE][0]['value'], t('Correct text displays for version.'));
+ $this->assertText($node->body[LANGUAGE_NOT_SPECIFIED][0]['value'], t('Correct text displays for version.'));
// Confirm the correct log message appears on "revisions overview" page.
$this->drupalGet("node/$node->nid/revisions");
@@ -205,7 +222,7 @@ class NodeRevisionsTestCase extends DrupalWebTestCase {
array('@type' => 'Basic page', '%title' => $nodes[1]->title,
'%revision-date' => format_date($nodes[1]->revision_timestamp))), t('Revision reverted.'));
$reverted_node = node_load($node->nid);
- $this->assertTrue(($nodes[1]->body[LANGUAGE_NONE][0]['value'] == $reverted_node->body[LANGUAGE_NONE][0]['value']), t('Node reverted correctly.'));
+ $this->assertTrue(($nodes[1]->body[LANGUAGE_NOT_SPECIFIED][0]['value'] == $reverted_node->body[LANGUAGE_NOT_SPECIFIED][0]['value']), t('Node reverted correctly.'));
// Confirm revisions delete properly.
$this->drupalPost("node/$node->nid/revisions/{$nodes[1]->vid}/delete", array(), t('Delete'));
@@ -264,7 +281,7 @@ class NodeRevisionsTestCase extends DrupalWebTestCase {
}
}
-class PageEditTestCase extends DrupalWebTestCase {
+class PageEditTestCase extends NodeWebTestCase {
protected $web_user;
protected $admin_user;
@@ -289,7 +306,7 @@ class PageEditTestCase extends DrupalWebTestCase {
function testPageEdit() {
$this->drupalLogin($this->web_user);
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$title_key = "title";
$body_key = "body[$langcode][0][value]";
// Create node to edit.
@@ -357,7 +374,7 @@ class PageEditTestCase extends DrupalWebTestCase {
$this->drupalLogin($this->admin_user);
// Create node to edit.
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$body_key = "body[$langcode][0][value]";
$edit = array();
$edit['title'] = $this->randomName(8);
@@ -396,7 +413,7 @@ class PageEditTestCase extends DrupalWebTestCase {
}
}
-class PagePreviewTestCase extends DrupalWebTestCase {
+class PagePreviewTestCase extends NodeWebTestCase {
public static function getInfo() {
return array(
'name' => 'Node preview',
@@ -416,7 +433,7 @@ class PagePreviewTestCase extends DrupalWebTestCase {
* Check the node preview functionality.
*/
function testPagePreview() {
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$title_key = "title";
$body_key = "body[$langcode][0][value]";
@@ -440,7 +457,7 @@ class PagePreviewTestCase extends DrupalWebTestCase {
* Check the node preview functionality, when using revisions.
*/
function testPagePreviewWithRevisions() {
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$title_key = "title";
$body_key = "body[$langcode][0][value]";
// Force revision on "Basic page" content.
@@ -467,7 +484,7 @@ class PagePreviewTestCase extends DrupalWebTestCase {
}
}
-class NodeCreationTestCase extends DrupalWebTestCase {
+class NodeCreationTestCase extends NodeWebTestCase {
public static function getInfo() {
return array(
'name' => 'Node creation',
@@ -478,7 +495,7 @@ class NodeCreationTestCase extends DrupalWebTestCase {
function setUp() {
// Enable dummy module that implements hook_node_insert for exceptions.
- parent::setUp('node_test_exception');
+ parent::setUp(array('node_test_exception', 'dblog'));
$web_user = $this->drupalCreateUser(array('create page content', 'edit own page content'));
$this->drupalLogin($web_user);
@@ -490,7 +507,7 @@ class NodeCreationTestCase extends DrupalWebTestCase {
function testNodeCreation() {
// Create a node.
$edit = array();
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$edit["title"] = $this->randomName(8);
$edit["body[$langcode][0][value]"] = $this->randomName(16);
$this->drupalPost('node/add/page', $edit, t('Save'));
@@ -512,7 +529,7 @@ class NodeCreationTestCase extends DrupalWebTestCase {
'uid' => $this->loggedInUser->uid,
'name' => $this->loggedInUser->name,
'type' => 'page',
- 'langcode' => LANGUAGE_NONE,
+ 'langcode' => LANGUAGE_NOT_SPECIFIED,
'title' => 'testing_transaction_exception',
);
@@ -545,7 +562,7 @@ class NodeCreationTestCase extends DrupalWebTestCase {
}
}
-class PageViewTestCase extends DrupalWebTestCase {
+class PageViewTestCase extends NodeWebTestCase {
public static function getInfo() {
return array(
'name' => 'Node edit permissions',
@@ -584,7 +601,7 @@ class PageViewTestCase extends DrupalWebTestCase {
}
}
-class SummaryLengthTestCase extends DrupalWebTestCase {
+class SummaryLengthTestCase extends NodeWebTestCase {
public static function getInfo() {
return array(
'name' => 'Summary length',
@@ -599,7 +616,7 @@ class SummaryLengthTestCase extends DrupalWebTestCase {
function testSummaryLength() {
// Create a node to view.
$settings = array(
- 'body' => array(LANGUAGE_NONE => array(array('value' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam vitae arcu at leo cursus laoreet. Curabitur dui tortor, adipiscing malesuada tempor in, bibendum ac diam. Cras non tellus a libero pellentesque condimentum. What is a Drupalism? Suspendisse ac lacus libero. Ut non est vel nisl faucibus interdum nec sed leo. Pellentesque sem risus, vulputate eu semper eget, auctor in libero. Ut fermentum est vitae metus convallis scelerisque. Phasellus pellentesque rhoncus tellus, eu dignissim purus posuere id. Quisque eu fringilla ligula. Morbi ullamcorper, lorem et mattis egestas, tortor neque pretium velit, eget eleifend odio turpis eu purus. Donec vitae metus quis leo pretium tincidunt a pulvinar sem. Morbi adipiscing laoreet mauris vel placerat. Nullam elementum, nisl sit amet scelerisque malesuada, dolor nunc hendrerit quam, eu ultrices erat est in orci. Curabitur feugiat egestas nisl sed accumsan.'))),
+ 'body' => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam vitae arcu at leo cursus laoreet. Curabitur dui tortor, adipiscing malesuada tempor in, bibendum ac diam. Cras non tellus a libero pellentesque condimentum. What is a Drupalism? Suspendisse ac lacus libero. Ut non est vel nisl faucibus interdum nec sed leo. Pellentesque sem risus, vulputate eu semper eget, auctor in libero. Ut fermentum est vitae metus convallis scelerisque. Phasellus pellentesque rhoncus tellus, eu dignissim purus posuere id. Quisque eu fringilla ligula. Morbi ullamcorper, lorem et mattis egestas, tortor neque pretium velit, eget eleifend odio turpis eu purus. Donec vitae metus quis leo pretium tincidunt a pulvinar sem. Morbi adipiscing laoreet mauris vel placerat. Nullam elementum, nisl sit amet scelerisque malesuada, dolor nunc hendrerit quam, eu ultrices erat est in orci. Curabitur feugiat egestas nisl sed accumsan.'))),
'promote' => 1,
);
$node = $this->drupalCreateNode($settings);
@@ -626,7 +643,7 @@ class SummaryLengthTestCase extends DrupalWebTestCase {
}
}
-class NodeTitleXSSTestCase extends DrupalWebTestCase {
+class NodeTitleXSSTestCase extends NodeWebTestCase {
public static function getInfo() {
return array(
'name' => 'Node title XSS filtering',
@@ -660,7 +677,7 @@ class NodeTitleXSSTestCase extends DrupalWebTestCase {
}
}
-class NodeBlockTestCase extends DrupalWebTestCase {
+class NodeBlockTestCase extends NodeWebTestCase {
public static function getInfo() {
return array(
'name' => 'Block availability',
@@ -670,7 +687,7 @@ class NodeBlockTestCase extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp();
+ parent::setUp(array('block'));
// Create and login user
$admin_user = $this->drupalCreateUser(array('administer blocks'));
@@ -693,7 +710,7 @@ class NodeBlockTestCase extends DrupalWebTestCase {
/**
* Check that the post information displays when enabled for a content type.
*/
-class NodePostSettingsTestCase extends DrupalWebTestCase {
+class NodePostSettingsTestCase extends NodeWebTestCase {
public static function getInfo() {
return array(
'name' => 'Node post information display',
@@ -721,14 +738,14 @@ class NodePostSettingsTestCase extends DrupalWebTestCase {
// Create a node.
$edit = array();
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$edit["title"] = $this->randomName(8);
$edit["body[$langcode][0][value]"] = $this->randomName(16);
$this->drupalPost('node/add/page', $edit, t('Save'));
// Check that the post information is displayed.
$node = $this->drupalGetNodeByTitle($edit["title"]);
- $elements = $this->xpath('//div[contains(@class,:class)]', array(':class' => 'submitted'));
+ $elements = $this->xpath('//*[contains(@class,:class)]', array(':class' => 'submitted'));
$this->assertEqual(count($elements), 1, t('Post information is displayed.'));
}
@@ -744,7 +761,7 @@ class NodePostSettingsTestCase extends DrupalWebTestCase {
// Create a node.
$edit = array();
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$edit["title"] = $this->randomName(8);
$edit["body[$langcode][0][value]"] = $this->randomName(16);
$this->drupalPost('node/add/page', $edit, t('Save'));
@@ -762,7 +779,7 @@ class NodePostSettingsTestCase extends DrupalWebTestCase {
* added to the node->content array, then verify that the data appears on the
* sitewide RSS feed at rss.xml.
*/
-class NodeRSSContentTestCase extends DrupalWebTestCase {
+class NodeRSSContentTestCase extends NodeWebTestCase {
public static function getInfo() {
return array(
'name' => 'Node RSS Content',
@@ -823,7 +840,7 @@ class NodeRSSContentTestCase extends DrupalWebTestCase {
* @todo Cover hook_node_access in a separate test class.
* hook_node_access_records is covered in another test class.
*/
-class NodeAccessUnitTest extends DrupalWebTestCase {
+class NodeAccessUnitTest extends NodeWebTestCase {
public static function getInfo() {
return array(
'name' => 'Node access',
@@ -890,7 +907,7 @@ class NodeAccessUnitTest extends DrupalWebTestCase {
/**
* Test case to verify hook_node_access_records functionality.
*/
-class NodeAccessRecordsUnitTest extends DrupalWebTestCase {
+class NodeAccessRecordsUnitTest extends NodeWebTestCase {
public static function getInfo() {
return array(
'name' => 'Node access records',
@@ -973,7 +990,9 @@ class NodeAccessRecordsUnitTest extends DrupalWebTestCase {
/**
* Tests for Node Access with a non-node base table.
*/
-class NodeAccessBaseTableTestCase extends DrupalWebTestCase {
+class NodeAccessBaseTableTestCase extends NodeWebTestCase {
+ // Requires tags taxonomy field.
+ protected $profile = 'standard';
public static function getInfo() {
return array(
@@ -1132,7 +1151,7 @@ class NodeAccessBaseTableTestCase extends DrupalWebTestCase {
/**
* Test case to check node save related functionality, including import-save
*/
-class NodeSaveTestCase extends DrupalWebTestCase {
+class NodeSaveTestCase extends NodeWebTestCase {
public static function getInfo() {
return array(
@@ -1164,7 +1183,7 @@ class NodeSaveTestCase extends DrupalWebTestCase {
$title = $this->randomName(8);
$node = array(
'title' => $title,
- 'body' => array(LANGUAGE_NONE => array(array('value' => $this->randomName(32)))),
+ 'body' => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => $this->randomName(32)))),
'uid' => $this->web_user->uid,
'type' => 'article',
'nid' => $test_nid,
@@ -1275,7 +1294,7 @@ class NodeSaveTestCase extends DrupalWebTestCase {
/**
* Tests related to node types.
*/
-class NodeTypeTestCase extends DrupalWebTestCase {
+class NodeTypeTestCase extends NodeWebTestCase {
public static function getInfo() {
return array(
'name' => 'Node types',
@@ -1284,6 +1303,10 @@ class NodeTypeTestCase extends DrupalWebTestCase {
);
}
+ function setUp() {
+ parent::setUp(array('field_ui'));
+ }
+
/**
* Ensure that node type functions (node_type_get_*) work correctly.
*
@@ -1378,7 +1401,7 @@ class NodeTypeTestCase extends DrupalWebTestCase {
$this->assertRaw('Body', t('Body field was found.'));
// Remove the body field.
- $this->drupalPost('admin/structure/types/manage/bar/fields/body/delete', NULL, t('Delete'));
+ $this->drupalPost('admin/structure/types/manage/bar/fields/body/delete', array(), t('Delete'));
// Resave the settings for this type.
$this->drupalPost('admin/structure/types/manage/bar', array(), t('Save content type'));
// Check that the body field doesn't exist.
@@ -1429,7 +1452,7 @@ class NodeTypeTestCase extends DrupalWebTestCase {
/**
* Test node type customizations persistence.
*/
-class NodeTypePersistenceTestCase extends DrupalWebTestCase {
+class NodeTypePersistenceTestCase extends NodeWebTestCase {
public static function getInfo() {
return array(
'name' => 'Node type persist',
@@ -1505,7 +1528,7 @@ class NodeTypePersistenceTestCase extends DrupalWebTestCase {
/**
* Rebuild the node_access table.
*/
-class NodeAccessRebuildTestCase extends DrupalWebTestCase {
+class NodeAccessRebuildTestCase extends NodeWebTestCase {
public static function getInfo() {
return array(
'name' => 'Node access rebuild',
@@ -1533,7 +1556,7 @@ class NodeAccessRebuildTestCase extends DrupalWebTestCase {
/**
* Test node administration page functionality.
*/
-class NodeAdminTestCase extends DrupalWebTestCase {
+class NodeAdminTestCase extends NodeWebTestCase {
public static function getInfo() {
return array(
'name' => 'Node administration',
@@ -1698,7 +1721,7 @@ class NodeAdminTestCase extends DrupalWebTestCase {
/**
* Test node title.
*/
-class NodeTitleTestCase extends DrupalWebTestCase {
+class NodeTitleTestCase extends NodeWebTestCase {
protected $admin_user;
public static function getInfo() {
@@ -1710,8 +1733,8 @@ class NodeTitleTestCase extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp();
- $this->admin_user = $this->drupalCreateUser(array('administer nodes', 'create article content', 'create page content'));
+ parent::setUp(array('comment'));
+ $this->admin_user = $this->drupalCreateUser(array('administer nodes', 'create article content', 'create page content', 'post comments'));
$this->drupalLogin($this->admin_user);
}
@@ -1738,7 +1761,7 @@ class NodeTitleTestCase extends DrupalWebTestCase {
$this->assertEqual(current($this->xpath($xpath)), $node->title, 'Node breadcrumb is equal to node title.', 'Node');
// Test node title in comment preview.
- $this->assertEqual(current($this->xpath('//div[@id=:id]/h2/a', array(':id' => 'node-' . $node->nid))), $node->title, 'Node preview title is equal to node title.', 'Node');
+ $this->assertEqual(current($this->xpath('//article[@id=:id]/h2/a', array(':id' => 'node-' . $node->nid))), $node->title, 'Node preview title is equal to node title.', 'Node');
// Test node title is clickable on teaser list (/node).
$this->drupalGet('node');
@@ -1773,7 +1796,7 @@ class NodeFeedTestCase extends DrupalWebTestCase {
/**
* Functional tests for the node module blocks.
*/
-class NodeBlockFunctionalTest extends DrupalWebTestCase {
+class NodeBlockFunctionalTest extends NodeWebTestCase {
public static function getInfo() {
return array(
'name' => 'Node blocks',
@@ -1783,7 +1806,7 @@ class NodeBlockFunctionalTest extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('node', 'block');
+ parent::setUp(array('block'));
// Create users and test node.
$this->admin_user = $this->drupalCreateUser(array('administer content types', 'administer nodes', 'administer blocks'));
@@ -1946,7 +1969,7 @@ class MultiStepNodeFormBasicOptionsTest extends DrupalWebTestCase {
/**
* Test to ensure that a node's content is always rebuilt.
*/
-class NodeBuildContent extends DrupalWebTestCase {
+class NodeBuildContent extends NodeWebTestCase {
public static function getInfo() {
return array(
@@ -1974,7 +1997,7 @@ class NodeBuildContent extends DrupalWebTestCase {
/**
* Tests node_query_node_access_alter().
*/
-class NodeQueryAlter extends DrupalWebTestCase {
+class NodeQueryAlter extends NodeWebTestCase {
public static function getInfo() {
return array(
@@ -2165,7 +2188,7 @@ class NodeQueryAlter extends DrupalWebTestCase {
/**
* Tests node_query_entity_field_access_alter().
*/
-class NodeEntityFieldQueryAlter extends DrupalWebTestCase {
+class NodeEntityFieldQueryAlter extends NodeWebTestCase {
public static function getInfo() {
return array(
@@ -2192,13 +2215,13 @@ class NodeEntityFieldQueryAlter extends DrupalWebTestCase {
// Creating 4 nodes with an entity field so we can test that sort of query
// alter. All field values starts with 'A' so we can identify and fetch them
// in the node_access_test module.
- $settings = array('langcode' => LANGUAGE_NONE);
+ $settings = array('langcode' => LANGUAGE_NOT_SPECIFIED);
for ($i = 0; $i < 4; $i++) {
$body = array(
'value' => 'A' . $this->randomName(32),
'format' => filter_default_format(),
);
- $settings['body'][LANGUAGE_NONE][0] = $body;
+ $settings['body'][LANGUAGE_NOT_SPECIFIED][0] = $body;
$this->drupalCreateNode($settings);
}
@@ -2229,7 +2252,7 @@ class NodeEntityFieldQueryAlter extends DrupalWebTestCase {
/**
* Test node token replacement in strings.
*/
-class NodeTokenReplaceTestCase extends DrupalWebTestCase {
+class NodeTokenReplaceTestCase extends NodeWebTestCase {
public static function getInfo() {
return array(
'name' => 'Node token replacement',
@@ -2254,7 +2277,7 @@ class NodeTokenReplaceTestCase extends DrupalWebTestCase {
'type' => 'article',
'uid' => $account->uid,
'title' => '
',
- 'body' => array(LANGUAGE_NONE => array(array('value' => $this->randomName(32), 'summary' => $this->randomName(16)))),
+ 'body' => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => $this->randomName(32), 'summary' => $this->randomName(16)))),
);
$node = $this->drupalCreateNode($settings);
@@ -2306,7 +2329,7 @@ class NodeTokenReplaceTestCase extends DrupalWebTestCase {
/**
* Tests user permissions for node revisions.
*/
-class NodeRevisionPermissionsTestCase extends DrupalWebTestCase {
+class NodeRevisionPermissionsTestCase extends NodeWebTestCase {
protected $node_revisions = array();
protected $accounts = array();
@@ -2401,3 +2424,89 @@ class NodeRevisionPermissionsTestCase extends DrupalWebTestCase {
$GLOBALS['user'] = $original_user;
}
}
+
+/**
+ * Tests pagination with a node access module enabled.
+ */
+class NodeAccessPagerTestCase extends DrupalWebTestCase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Node access pagination',
+ 'description' => 'Test access controlled node views have the right amount of comment pages.',
+ 'group' => 'Node',
+ );
+ }
+
+ public function setUp() {
+ parent::setUp('node_access_test', 'comment', 'forum');
+ node_access_rebuild();
+ $this->web_user = $this->drupalCreateUser(array('access content', 'access comments', 'node test view'));
+ }
+
+ /**
+ * Tests the comment pager for nodes with multiple grants per realm.
+ */
+ public function testCommentPager() {
+ // Create a node.
+ $node = $this->drupalCreateNode();
+
+ // Create 60 comments.
+ for ($i = 0; $i < 60; $i++) {
+ $comment = entity_create('comment', array(
+ 'nid' => $node->nid,
+ 'subject' => $this->randomName(),
+ 'comment_body' => array(
+ LANGUAGE_NOT_SPECIFIED => array(
+ array('value' => $this->randomName()),
+ ),
+ ),
+ ));
+ $comment->save();
+ }
+
+ $this->drupalLogin($this->web_user);
+
+ // View the node page. With the default 50 comments per page there should
+ // be two pages (0, 1) but no third (2) page.
+ $this->drupalGet('node/' . $node->nid);
+ $this->assertText($node->title, t('Node title found.'));
+ $this->assertText(t('Comments'), t('Has a comments section.'));
+ $this->assertRaw('page=1', t('Secound page exists.'));
+ $this->assertNoRaw('page=2', t('No third page exists.'));
+ }
+
+ /**
+ * Tests the forum node pager for nodes with multiple grants per realm.
+ */
+ public function testForumPager() {
+ // Lookup the forums vocabulary vid.
+ $vid = variable_get('forum_nav_vocabulary', 0);
+ $this->assertTrue($vid, t('Forum navigation vocabulary found.'));
+
+ // Lookup the general discussion term.
+ $tree = taxonomy_get_tree($vid, 0, 1);
+ $tid = reset($tree)->tid;
+ $this->assertTrue($tid, t('General discussion term found.'));
+
+ // Create 30 nodes.
+ for ($i = 0; $i < 30; $i++) {
+ $this->drupalCreateNode(array(
+ 'nid' => NULL,
+ 'type' => 'forum',
+ 'taxonomy_forums' => array(
+ LANGUAGE_NOT_SPECIFIED => array(
+ array('tid' => $tid, 'vid' => $vid, 'vocabulary_machine_name' => 'forums'),
+ ),
+ ),
+ ));
+ }
+
+ // View the general discussion forum page. With the default 25 nodes per
+ // page there should be two pages for 30 nodes, no more.
+ $this->drupalLogin($this->web_user);
+ $this->drupalGet('forum/' . $tid);
+ $this->assertRaw('page=1', t('Secound page exists.'));
+ $this->assertNoRaw('page=2', t('No third page exists.'));
+ }
+}
diff --git a/core/modules/node/tests/node_access_test.module b/core/modules/node/tests/node_access_test.module
index c1e7edd..d9e6e2f 100644
--- a/core/modules/node/tests/node_access_test.module
+++ b/core/modules/node/tests/node_access_test.module
@@ -15,7 +15,7 @@ function node_access_test_node_grants($account, $op) {
// First grant a grant to the author for own content.
$grants['node_access_test_author'] = array($account->uid);
if ($op == 'view' && user_access('node test view', $account)) {
- $grants['node_access_test'] = array(8888);
+ $grants['node_access_test'] = array(8888, 8889);
}
if ($op == 'view' && $account->uid == variable_get('node_test_node_access_all_uid', 0)) {
$grants['node_access_all'] = array(0);
@@ -38,6 +38,14 @@ function node_access_test_node_access_records($node) {
'grant_delete' => 0,
'priority' => 0,
);
+ $grants[] = array(
+ 'realm' => 'node_access_test',
+ 'gid' => 8889,
+ 'grant_view' => 1,
+ 'grant_update' => 0,
+ 'grant_delete' => 0,
+ 'priority' => 0,
+ );
// For the author realm, the GID is equivalent to a UID, which
// means there are many many groups of just 1 user.
$grants[] = array(
diff --git a/core/modules/openid/openid.module b/core/modules/openid/openid.module
index d29d405..a8e99a0 100644
--- a/core/modules/openid/openid.module
+++ b/core/modules/openid/openid.module
@@ -268,8 +268,8 @@ function openid_form_user_register_form_alter(&$form, &$form_state) {
// specific) strings.
foreach (array_reverse($candidate_languages) as $candidate_language) {
if (isset($enabled_languages[$candidate_language])) {
- $form['locale']['language']['#type'] = 'hidden';
- $form['locale']['language']['#value'] = $candidate_language;
+ $form['locale']['preferred_langcode']['#type'] = 'hidden';
+ $form['locale']['preferred_langcode']['#value'] = $candidate_language;
}
}
}
diff --git a/core/modules/openid/openid.test b/core/modules/openid/openid.test
index 7f87b4b..7a4c9cf 100644
--- a/core/modules/openid/openid.test
+++ b/core/modules/openid/openid.test
@@ -9,6 +9,37 @@
* Base class for OpenID tests.
*/
abstract class OpenIDWebTestCase extends DrupalWebTestCase {
+ function setUp() {
+ $modules = func_get_args();
+ if (isset($modules[0]) && is_array($modules[0])) {
+ $modules = $modules[0];
+ }
+ $modules[] = 'block';
+ $modules[] = 'openid';
+ parent::setUp($modules);
+
+ // Enable user login block.
+ db_merge('block')
+ ->key(array(
+ 'module' => 'user',
+ 'delta' => 'login',
+ 'theme' => variable_get('theme_default', 'stark'),
+ ))
+ ->fields(array(
+ 'status' => 1,
+ 'weight' => 0,
+ 'region' => 'sidebar_first',
+ 'pages' => '',
+ 'cache' => -1,
+ ))
+ ->execute();
+
+ // Create Basic page and Article node types.
+ if ($this->profile != 'standard') {
+ $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
+ $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
+ }
+ }
/**
* Initiates the login procedure using the specified User-supplied Identity.
@@ -453,7 +484,7 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase {
$this->assertTrue($user, t('User was registered with right username.'));
$this->assertEqual($user->mail, 'john@example.com', t('User was registered with right email address.'));
$this->assertEqual($user->timezone, 'Europe/London', t('User was registered with right timezone.'));
- $this->assertEqual($user->language, 'en', t('User was registered with right language.'));
+ $this->assertEqual($user->preferred_langcode, 'en', t('User was registered with right language.'));
$this->assertFalse($user->data, t('No additional user info was saved.'));
$this->submitLoginForm($identity);
@@ -495,7 +526,7 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase {
$this->assertTrue($user, t('User was registered with right username.'));
$this->assertEqual($user->mail, 'john@example.com', t('User was registered with right email address.'));
$this->assertEqual($user->timezone, 'Europe/London', t('User was registered with right timezone.'));
- $this->assertEqual($user->language, 'en', t('User was registered with right language.'));
+ $this->assertEqual($user->preferred_langcode, 'en', t('User was registered with right language.'));
$this->assertFalse($user->data, t('No additional user info was saved.'));
$this->drupalLogout();
@@ -540,7 +571,7 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase {
$user = user_load_by_name('john');
$this->assertTrue($user, t('User was registered with right username.'));
- $this->assertFalse($user->language, t('No user language was saved.'));
+ $this->assertFalse($user->preferred_langcode, t('No user language was saved.'));
$this->assertFalse($user->data, t('No additional user info was saved.'));
// Follow the one-time login that was sent in the welcome e-mail.
@@ -580,7 +611,7 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase {
$user = user_load_by_name('john');
$this->assertTrue($user, t('User was registered with right username.'));
- $this->assertFalse($user->language, t('No user language was saved.'));
+ $this->assertFalse($user->preferred_langcode, t('No user language was saved.'));
$this->assertFalse($user->data, t('No additional user info was saved.'));
// Follow the one-time login that was sent in the welcome e-mail.
@@ -625,7 +656,7 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase {
$this->assertTrue($user, t('User was registered with right username.'));
$this->assertEqual($user->mail, 'john@example.com', t('User was registered with right email address.'));
$this->assertEqual($user->timezone, 'Europe/London', t('User was registered with right timezone.'));
- $this->assertEqual($user->language, 'en', t('User was registered with right language.'));
+ $this->assertEqual($user->preferred_langcode, 'en', t('User was registered with right language.'));
}
}
diff --git a/core/modules/overlay/overlay-parent.js b/core/modules/overlay/overlay-parent.js
index dd7b7ae..2e3b4f9 100644
--- a/core/modules/overlay/overlay-parent.js
+++ b/core/modules/overlay/overlay-parent.js
@@ -1,4 +1,3 @@
-
(function ($) {
/**
@@ -354,9 +353,14 @@ Drupal.overlay.isAdminLink = function (url) {
// Turn the list of administrative paths into a regular expression.
if (!this.adminPathRegExp) {
- var regExpPrefix = '' + Drupal.settings.pathPrefix + '(';
- var adminPaths = regExpPrefix + Drupal.settings.overlay.paths.admin.replace(/\s+/g, ')$|' + regExpPrefix) + ')$';
- var nonAdminPaths = regExpPrefix + Drupal.settings.overlay.paths.non_admin.replace(/\s+/g, ')$|'+ regExpPrefix) + ')$';
+ var prefix = '';
+ if (Drupal.settings.overlay.pathPrefixes.length) {
+ // Allow path prefixes used for language negatiation followed by slash,
+ // and the empty string.
+ prefix = '(' + Drupal.settings.overlay.pathPrefixes.join('/|') + '/|)';
+ }
+ var adminPaths = '^' + prefix + '(' + Drupal.settings.overlay.paths.admin.replace(/\s+/g, '|') + ')$';
+ var nonAdminPaths = '^' + prefix + '(' + Drupal.settings.overlay.paths.non_admin.replace(/\s+/g, '|') + ')$';
adminPaths = adminPaths.replace(/\*/g, '.*');
nonAdminPaths = nonAdminPaths.replace(/\*/g, '.*');
this.adminPathRegExp = new RegExp(adminPaths);
@@ -863,8 +867,13 @@ Drupal.overlay.getDisplacement = function (region) {
if (lastDisplaced.length) {
displacement = lastDisplaced.offset().top + lastDisplaced.outerHeight();
- // Remove height added by IE Shadow filter.
- if (lastDisplaced[0].filters && lastDisplaced[0].filters.length && lastDisplaced[0].filters.item('DXImageTransform.Microsoft.Shadow')) {
+ // In modern browsers (including IE9), when box-shadow is defined, use the
+ // normal height.
+ var cssBoxShadowValue = lastDisplaced.css('box-shadow');
+ var boxShadow = (typeof cssBoxShadowValue !== 'undefined' && cssBoxShadowValue !== 'none');
+ // In IE8 and below, we use the shadow filter to apply box-shadow styles to
+ // the toolbar. It adds some extra height that we need to remove.
+ if (!boxShadow && /DXImageTransform\.Microsoft\.Shadow/.test(lastDisplaced.css('filter'))) {
displacement -= lastDisplaced[0].filters.item('DXImageTransform.Microsoft.Shadow').strength;
displacement = Math.max(0, displacement);
}
diff --git a/core/modules/overlay/overlay.module b/core/modules/overlay/overlay.module
index 8f62c01..a9813af 100644
--- a/core/modules/overlay/overlay.module
+++ b/core/modules/overlay/overlay.module
@@ -638,6 +638,13 @@ function overlay_overlay_parent_initialize() {
$type = str_replace('
', variable_get('site_frontpage', 'user'), $type);
}
drupal_add_js(array('overlay' => array('paths' => $paths)), 'setting');
+ $path_prefixes = array();
+ if (module_exists('locale') && variable_get('locale_language_negotiation_url_part', LANGUAGE_NEGOTIATION_URL_PREFIX) == LANGUAGE_NEGOTIATION_URL_PREFIX) {
+ // Skip the empty string indicating the default language. We always accept
+ // paths without a prefix.
+ $path_prefixes = array_values(array_filter(locale_language_negotiation_url_prefixes()));
+ }
+ drupal_add_js(array('overlay' => array('pathPrefixes' => $path_prefixes)), 'setting');
// Pass along the Ajax callback for rerendering sections of the parent window.
drupal_add_js(array('overlay' => array('ajaxCallback' => 'overlay-ajax')), 'setting');
}
diff --git a/core/modules/path/path.admin.inc b/core/modules/path/path.admin.inc
index 511c26d..fe122cc 100644
--- a/core/modules/path/path.admin.inc
+++ b/core/modules/path/path.admin.inc
@@ -16,7 +16,7 @@ function path_admin_overview($keys = NULL) {
$build['path_admin_filter_form'] = drupal_get_form('path_admin_filter_form', $keys);
// Enable language column if language.module is enabled or if we have any
// alias with a language.
- $alias_exists = (bool) db_query_range('SELECT 1 FROM {url_alias} WHERE langcode <> :langcode', 0, 1, array(':langcode' => LANGUAGE_NONE))->fetchField();
+ $alias_exists = (bool) db_query_range('SELECT 1 FROM {url_alias} WHERE langcode <> :langcode', 0, 1, array(':langcode' => LANGUAGE_NOT_SPECIFIED))->fetchField();
$multilanguage = (module_exists('language') || $alias_exists);
$header = array();
@@ -109,7 +109,7 @@ function path_admin_edit($path = array()) {
* @see path_admin_form_validate()
* @see path_admin_form_submit()
*/
-function path_admin_form($form, &$form_state, $path = array('source' => '', 'alias' => '', 'langcode' => LANGUAGE_NONE, 'pid' => NULL)) {
+function path_admin_form($form, &$form_state, $path = array('source' => '', 'alias' => '', 'langcode' => LANGUAGE_NOT_SPECIFIED, 'pid' => NULL)) {
$form['source'] = array(
'#type' => 'textfield',
'#title' => t('Existing system path'),
@@ -142,7 +142,7 @@ function path_admin_form($form, &$form_state, $path = array('source' => '', 'ali
'#type' => 'select',
'#title' => t('Language'),
'#options' => $language_options,
- '#empty_value' => LANGUAGE_NONE,
+ '#empty_value' => LANGUAGE_NOT_SPECIFIED,
'#empty_option' => t('- None -'),
'#default_value' => $path['langcode'],
'#weight' => -10,
@@ -198,7 +198,7 @@ function path_admin_form_validate($form, &$form_state) {
$pid = isset($form_state['values']['pid']) ? $form_state['values']['pid'] : 0;
// Language is only set if language.module is enabled, otherwise save for all
// languages.
- $langcode = isset($form_state['values']['langcode']) ? $form_state['values']['langcode'] : LANGUAGE_NONE;
+ $langcode = isset($form_state['values']['langcode']) ? $form_state['values']['langcode'] : LANGUAGE_NOT_SPECIFIED;
$has_alias = db_query("SELECT COUNT(alias) FROM {url_alias} WHERE pid <> :pid AND alias = :alias AND langcode = :langcode", array(
':pid' => $pid,
diff --git a/core/modules/path/path.module b/core/modules/path/path.module
index cdeece7..95f1fc0 100644
--- a/core/modules/path/path.module
+++ b/core/modules/path/path.module
@@ -97,7 +97,7 @@ function path_form_node_form_alter(&$form, $form_state) {
$path = array();
if (!empty($form['#node']->nid)) {
$conditions = array('source' => 'node/' . $form['#node']->nid);
- if ($form['#node']->langcode != LANGUAGE_NONE) {
+ if ($form['#node']->langcode != LANGUAGE_NOT_SPECIFIED) {
$conditions['langcode'] = $form['#node']->langcode;
}
$path = path_load($conditions);
@@ -109,7 +109,7 @@ function path_form_node_form_alter(&$form, $form_state) {
'pid' => NULL,
'source' => isset($form['#node']->nid) ? 'node/' . $form['#node']->nid : NULL,
'alias' => '',
- 'langcode' => isset($form['#node']->langcode) ? $form['#node']->langcode : LANGUAGE_NONE,
+ 'langcode' => isset($form['#node']->langcode) ? $form['#node']->langcode : LANGUAGE_NOT_SPECIFIED,
);
$form['path'] = array(
@@ -189,7 +189,7 @@ function path_node_insert($node) {
if (!empty($path['alias'])) {
// Ensure fields for programmatic executions.
$path['source'] = 'node/' . $node->nid;
- $path['langcode'] = isset($node->langcode) ? $node->langcode : LANGUAGE_NONE;
+ $path['langcode'] = isset($node->langcode) ? $node->langcode : LANGUAGE_NOT_SPECIFIED;
path_save($path);
}
}
@@ -210,7 +210,7 @@ function path_node_update($node) {
if (!empty($path['alias'])) {
// Ensure fields for programmatic executions.
$path['source'] = 'node/' . $node->nid;
- $path['langcode'] = isset($node->langcode) ? $node->langcode : LANGUAGE_NONE;
+ $path['langcode'] = isset($node->langcode) ? $node->langcode : LANGUAGE_NOT_SPECIFIED;
path_save($path);
}
}
@@ -238,7 +238,7 @@ function path_form_taxonomy_form_term_alter(&$form, $form_state) {
'pid' => NULL,
'source' => isset($form['#term']['tid']) ? 'taxonomy/term/' . $form['#term']['tid'] : NULL,
'alias' => '',
- 'langcode' => LANGUAGE_NONE,
+ 'langcode' => LANGUAGE_NOT_SPECIFIED,
);
$form['path'] = array(
'#access' => user_access('create url aliases') || user_access('administer url aliases'),
@@ -270,7 +270,7 @@ function path_taxonomy_term_insert($term) {
if (!empty($path['alias'])) {
// Ensure fields for programmatic executions.
$path['source'] = 'taxonomy/term/' . $term->tid;
- $path['langcode'] = LANGUAGE_NONE;
+ $path['langcode'] = LANGUAGE_NOT_SPECIFIED;
path_save($path);
}
}
@@ -291,7 +291,7 @@ function path_taxonomy_term_update($term) {
if (!empty($path['alias'])) {
// Ensure fields for programmatic executions.
$path['source'] = 'taxonomy/term/' . $term->tid;
- $path['langcode'] = LANGUAGE_NONE;
+ $path['langcode'] = LANGUAGE_NOT_SPECIFIED;
path_save($path);
}
}
diff --git a/core/modules/path/path.test b/core/modules/path/path.test
index 7b6b2f2..32220ee 100644
--- a/core/modules/path/path.test
+++ b/core/modules/path/path.test
@@ -6,6 +6,24 @@
*/
class PathTestCase extends DrupalWebTestCase {
+ function setUp() {
+ $modules = func_get_args();
+ if (isset($modules[0]) && is_array($modules[0])) {
+ $modules = $modules[0];
+ }
+ $modules[] = 'node';
+ $modules[] = 'path';
+ parent::setUp($modules);
+
+ // Create Basic page and Article node types.
+ if ($this->profile != 'standard') {
+ $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
+ $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
+ }
+ }
+}
+
+class PathAliasTestCase extends PathTestCase {
public static function getInfo() {
return array(
'name' => 'Path alias functionality',
@@ -184,7 +202,7 @@ class PathTestCase extends DrupalWebTestCase {
/**
* Test URL aliases for taxonomy terms.
*/
-class PathTaxonomyTermTestCase extends DrupalWebTestCase {
+class PathTaxonomyTermTestCase extends PathTestCase {
public static function getInfo() {
return array(
'name' => 'Taxonomy term URL aliases',
@@ -194,7 +212,14 @@ class PathTaxonomyTermTestCase extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('path', 'taxonomy');
+ parent::setUp(array('taxonomy'));
+
+ // Create a Tags vocabulary for the Article node type.
+ $vocabulary = (object) array(
+ 'name' => t('Tags'),
+ 'machine_name' => 'tags',
+ );
+ taxonomy_vocabulary_save($vocabulary);
// Create and login user.
$web_user = $this->drupalCreateUser(array('administer url aliases', 'administer taxonomy', 'access administration pages'));
@@ -245,7 +270,7 @@ class PathTaxonomyTermTestCase extends DrupalWebTestCase {
}
}
-class PathLanguageTestCase extends DrupalWebTestCase {
+class PathLanguageTestCase extends PathTestCase {
public static function getInfo() {
return array(
'name' => 'Path aliases with translated nodes',
@@ -296,7 +321,7 @@ class PathLanguageTestCase extends DrupalWebTestCase {
$this->drupalGet('node/' . $english_node->nid . '/translate');
$this->clickLink(t('add translation'));
$edit = array();
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$edit["title"] = $this->randomName();
$edit["body[$langcode][0][value]"] = $this->randomName();
$french_alias = $this->randomName();
@@ -334,7 +359,7 @@ class PathLanguageTestCase extends DrupalWebTestCase {
$this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings'));
// Change user language preference.
- $edit = array('language' => 'fr');
+ $edit = array('preferred_langcode' => 'fr');
$this->drupalPost("user/{$this->web_user->uid}/edit", $edit, t('Save'));
// Check that the English alias works. In this situation French is the
@@ -388,7 +413,7 @@ class PathLanguageTestCase extends DrupalWebTestCase {
/**
* Tests the user interface for creating path aliases, with languages.
*/
-class PathLanguageUITestCase extends DrupalWebTestCase {
+class PathLanguageUITestCase extends PathTestCase {
public static function getInfo() {
return array(
'name' => 'Path aliases with languages',
@@ -464,7 +489,7 @@ class PathLanguageUITestCase extends DrupalWebTestCase {
/**
* Tests that paths are not prefixed on a monolingual site.
*/
-class PathMonolingualTestCase extends DrupalWebTestCase {
+class PathMonolingualTestCase extends PathTestCase {
public static function getInfo() {
return array(
'name' => 'Paths on non-English monolingual sites',
diff --git a/core/modules/php/php.test b/core/modules/php/php.test
index 50fb552..f6009c7 100644
--- a/core/modules/php/php.test
+++ b/core/modules/php/php.test
@@ -14,6 +14,9 @@ class PHPTestCase extends DrupalWebTestCase {
function setUp() {
parent::setUp('php');
+ // Create Basic page node type.
+ $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
+
// Create and login admin user.
$admin_user = $this->drupalCreateUser(array('administer filters'));
$this->drupalLogin($admin_user);
@@ -43,7 +46,7 @@ class PHPTestCase extends DrupalWebTestCase {
* @return stdObject Node object.
*/
function createNodeWithCode() {
- return $this->drupalCreateNode(array('body' => array(LANGUAGE_NONE => array(array('value' => '')))));
+ return $this->drupalCreateNode(array('body' => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => '')))));
}
}
@@ -73,11 +76,11 @@ class PHPFilterTestCase extends PHPTestCase {
// Make sure that the PHP code shows up as text.
$this->drupalGet('node/' . $node->nid);
- $this->assertText('print "SimpleTest PHP was executed!"', t('PHP code is displayed.'));
+ $this->assertText('php print');
// Change filter to PHP filter and see that PHP code is evaluated.
$edit = array();
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$edit["body[$langcode][0][format]"] = $this->php_code_format->format;
$this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
$this->assertRaw(t('Basic page %title has been updated.', array('%title' => $node->title)), t('PHP code filter turned on.'));
diff --git a/core/modules/poll/poll-results.tpl.php b/core/modules/poll/poll-results.tpl.php
index bb4cee3..4eb0fe2 100644
--- a/core/modules/poll/poll-results.tpl.php
+++ b/core/modules/poll/poll-results.tpl.php
@@ -21,7 +21,9 @@
-
+
+
+
$votes)); ?>
diff --git a/core/modules/poll/poll.admin.css b/core/modules/poll/poll.admin.css
new file mode 100644
index 0000000..f118de3
--- /dev/null
+++ b/core/modules/poll/poll.admin.css
@@ -0,0 +1,17 @@
+
+/**
+ * @file
+ * Admin stylesheet for the Poll module.
+ */
+
+.node-form #edit-poll-more {
+ margin: 0;
+}
+.node-form #poll-choice-table .form-text {
+ display: inline;
+ width: auto;
+}
+.node-form #poll-choice-table td.choice-flag {
+ white-space: nowrap;
+ width: 4em;
+}
diff --git a/core/modules/poll/poll.base-rtl.css b/core/modules/poll/poll.base-rtl.css
new file mode 100644
index 0000000..7c737a9
--- /dev/null
+++ b/core/modules/poll/poll.base-rtl.css
@@ -0,0 +1,9 @@
+
+/**
+ * @file
+ * Right-to-left specfic base stylesheet for the Poll module.
+ */
+
+.poll .bar .foreground {
+ float: right;
+}
diff --git a/core/modules/poll/poll.base.css b/core/modules/poll/poll.base.css
new file mode 100644
index 0000000..1d24c67
--- /dev/null
+++ b/core/modules/poll/poll.base.css
@@ -0,0 +1,19 @@
+
+/**
+ * @file
+ * Base stylesheet for the Poll module.
+ */
+
+.poll {
+ overflow: hidden;
+}
+.poll .bar {
+ height: 1em;
+ margin: 1px 0;
+ background-color: #ddd;
+}
+.poll .bar .foreground {
+ background-color: #000;
+ height: 1em;
+ float: left; /* LTR */
+}
diff --git a/core/modules/poll/poll.css b/core/modules/poll/poll.css
deleted file mode 100644
index 6abcaf5..0000000
--- a/core/modules/poll/poll.css
+++ /dev/null
@@ -1,49 +0,0 @@
-
-.poll {
- overflow: hidden;
-}
-.poll .bar {
- height: 1em;
- margin: 1px 0;
- background-color: #ddd;
-}
-.poll .bar .foreground {
- background-color: #000;
- height: 1em;
- float: left; /* LTR */
-}
-.poll .links {
- text-align: center;
-}
-.poll .percent {
- text-align: right; /* LTR */
-}
-.poll .total {
- text-align: center;
-}
-.poll .vote-form {
- text-align: center;
-}
-.poll .vote-form {
- text-align: left; /* LTR */
-}
-.poll .vote-form .poll-title {
- font-weight: bold;
-}
-.node-form #edit-poll-more {
- margin: 0;
-}
-.node-form #poll-choice-table .form-text {
- display: inline;
- width: auto;
-}
-.node-form #poll-choice-table td.choice-flag {
- white-space: nowrap;
- width: 4em;
-}
-td.poll-chtext {
- width: 80%;
-}
-td.poll-chvotes .form-text {
- width: 85%;
-}
diff --git a/core/modules/poll/poll.info b/core/modules/poll/poll.info
index dbdd621..99f778c 100644
--- a/core/modules/poll/poll.info
+++ b/core/modules/poll/poll.info
@@ -5,4 +5,5 @@ version = VERSION
core = 8.x
dependencies[] = node
files[] = poll.test
-stylesheets[all][] = poll.css
+stylesheets[all][] = poll.base.css
+stylesheets[all][] = poll.theme.css
diff --git a/core/modules/poll/poll.module b/core/modules/poll/poll.module
index 84a24d5..328f5eb 100644
--- a/core/modules/poll/poll.module
+++ b/core/modules/poll/poll.module
@@ -330,6 +330,9 @@ function poll_form($node, &$form_state) {
'#options' => $duration,
'#description' => t('After this period, the poll will be closed automatically.'),
);
+ $form['#attached']['css'] = array(
+ drupal_get_path('module', 'poll') . '/poll.admin.css',
+ );
return $form;
}
@@ -823,7 +826,8 @@ function poll_view_results($node, $view_mode, $block = FALSE) {
$poll_results[] = array(
'#theme' => 'meter',
- '#prefix' => '' . check_plain($choice['chtext']) . '
',
+ '#prefix' => '' . check_plain($choice['chtext']) . "\n" . '',
+ '#suffix' => "\n",
'#display_value' => t('!percentage%', array('!percentage' => $percentage)) . $display_votes,
'#min' => 0,
'#max' => $total_votes,
diff --git a/core/modules/poll/poll.test b/core/modules/poll/poll.test
index ad63d0f..ace8d56 100644
--- a/core/modules/poll/poll.test
+++ b/core/modules/poll/poll.test
@@ -5,7 +5,16 @@
* Tests for poll.module.
*/
-class PollTestCase extends DrupalWebTestCase {
+class PollWebTestCase extends DrupalWebTestCase {
+ function setUp() {
+ $modules = func_get_args();
+ if (isset($modules[0]) && is_array($modules[0])) {
+ $modules = $modules[0];
+ }
+ $modules[] = 'node';
+ $modules[] = 'poll';
+ parent::setUp($modules);
+ }
/**
* Creates a poll.
@@ -76,7 +85,7 @@ class PollTestCase extends DrupalWebTestCase {
* The title for the poll node.
* @param $choices
* An array containing poll choices, as generated by
- * PollTestCase::_generateChoices().
+ * PollWebTestCase::_generateChoices().
* @param $index
* (optional) The amount/number of already submitted poll choices. Defaults
* to 0.
@@ -120,14 +129,14 @@ class PollTestCase extends DrupalWebTestCase {
*
* @param $choices
* An array containing poll choices, as generated by
- * PollTestCase::_generateChoices().
+ * PollWebTestCase::_generateChoices().
* @param $index
* (optional) The amount/number of already submitted poll choices. Defaults
* to 0.
* @param $preview
* (optional) Whether to also check the poll preview.
*
- * @see PollTestCase::_pollGenerateEdit()
+ * @see PollWebTestCase::_pollGenerateEdit()
*/
function assertPollChoiceOrder(array $choices, $index = 0, $preview = FALSE) {
$expected = array();
@@ -181,7 +190,7 @@ class PollTestCase extends DrupalWebTestCase {
}
}
-class PollCreateTestCase extends PollTestCase {
+class PollCreateTestCase extends PollWebTestCase {
public static function getInfo() {
return array(
'name' => 'Poll create',
@@ -190,10 +199,6 @@ class PollCreateTestCase extends PollTestCase {
);
}
- function setUp() {
- parent::setUp('poll');
- }
-
function testPollCreate() {
$title = $this->randomName();
$choices = $this->_generateChoices(7);
@@ -228,10 +233,10 @@ class PollCreateTestCase extends PollTestCase {
$this->clickLink($title);
$this->assertText($new_option, 'New option found.');
- $option = $this->xpath('//div[@id="node-1"]//article[@class="poll"]//div[@class="choice-title"]');
+ $option = $this->xpath('//article[@id="node-1"]//article[@class="poll"]//dt[@class="choice-title"]');
$this->assertEqual(end($option), $new_option, 'Last item is equal to new option.');
- $votes = $this->xpath('//div[@id="node-1"]//article[@class="poll"]//div[@class="percent"]');
+ $votes = $this->xpath('//article[@id="node-1"]//article[@class="poll"]//div[@class="percent"]');
$this->assertTrue(strpos(end($votes), $vote_count) > 0, t("Votes saved."));
}
@@ -287,7 +292,7 @@ class PollCreateTestCase extends PollTestCase {
}
}
-class PollVoteTestCase extends PollTestCase {
+class PollVoteTestCase extends PollWebTestCase {
public static function getInfo() {
return array(
'name' => 'Poll vote',
@@ -296,10 +301,6 @@ class PollVoteTestCase extends PollTestCase {
);
}
- function setUp() {
- parent::setUp('poll');
- }
-
function tearDown() {
parent::tearDown();
}
@@ -363,7 +364,7 @@ class PollVoteTestCase extends PollTestCase {
}
}
-class PollBlockTestCase extends PollTestCase {
+class PollBlockTestCase extends PollWebTestCase {
public static function getInfo() {
return array(
'name' => 'Block availability',
@@ -373,7 +374,7 @@ class PollBlockTestCase extends PollTestCase {
}
function setUp() {
- parent::setUp('poll');
+ parent::setUp(array('block'));
// Create and login user
$admin_user = $this->drupalCreateUser(array('administer blocks'));
@@ -444,7 +445,7 @@ class PollJSAddChoice extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('poll');
+ parent::setUp(array('poll'));
}
/**
@@ -471,7 +472,7 @@ class PollJSAddChoice extends DrupalWebTestCase {
}
}
-class PollVoteCheckHostname extends PollTestCase {
+class PollVoteCheckHostname extends PollWebTestCase {
public static function getInfo() {
return array(
'name' => 'User poll vote capability.',
@@ -481,7 +482,7 @@ class PollVoteCheckHostname extends PollTestCase {
}
function setUp() {
- parent::setUp('poll');
+ parent::setUp();
// Create and login user.
$this->admin_user = $this->drupalCreateUser(array('administer permissions', 'create poll content'));
@@ -496,7 +497,9 @@ class PollVoteCheckHostname extends PollTestCase {
// Enable page cache to verify that the result page is not saved in the
// cache when anonymous voting is allowed.
- variable_set('cache', 1);
+ $config = config('system.performance');
+ $config->set('cache', 1);
+ $config->save();
// Create poll.
$title = $this->randomName();
@@ -614,7 +617,7 @@ class PollVoteCheckHostname extends PollTestCase {
/**
* Test poll token replacement in strings.
*/
-class PollTokenReplaceTestCase extends PollTestCase {
+class PollTokenReplaceTestCase extends PollWebTestCase {
public static function getInfo() {
return array(
'name' => 'Poll token replacement',
@@ -623,10 +626,6 @@ class PollTokenReplaceTestCase extends PollTestCase {
);
}
- function setUp() {
- parent::setUp('poll');
- }
-
/**
* Creates a poll, then tests the tokens generated from it.
*/
@@ -700,7 +699,7 @@ class PollTokenReplaceTestCase extends PollTestCase {
}
}
-class PollExpirationTestCase extends PollTestCase {
+class PollExpirationTestCase extends PollWebTestCase {
public static function getInfo() {
return array(
'name' => 'Poll expiration',
@@ -709,10 +708,6 @@ class PollExpirationTestCase extends PollTestCase {
);
}
- function setUp() {
- parent::setUp('poll');
- }
-
function testAutoExpire() {
// Set up a poll.
$title = $this->randomName();
@@ -763,7 +758,7 @@ class PollExpirationTestCase extends PollTestCase {
}
}
-class PollDeleteChoiceTestCase extends PollTestCase {
+class PollDeleteChoiceTestCase extends PollWebTestCase {
public static function getInfo() {
return array(
'name' => 'Poll choice deletion',
@@ -772,10 +767,6 @@ class PollDeleteChoiceTestCase extends PollTestCase {
);
}
- function setUp() {
- parent::setUp('poll');
- }
-
function testChoiceRemoval() {
// Set up a poll with three choices.
$title = $this->randomName();
@@ -802,7 +793,7 @@ class PollDeleteChoiceTestCase extends PollTestCase {
/**
* Tests poll translation logic.
*/
-class PollTranslateTestCase extends PollTestCase {
+class PollTranslateTestCase extends PollWebTestCase {
public static function getInfo() {
return array(
'name' => 'Poll translation',
@@ -812,7 +803,7 @@ class PollTranslateTestCase extends PollTestCase {
}
function setUp() {
- parent::setUp('poll', 'translation');
+ parent::setUp(array('translation'));
}
/**
diff --git a/core/modules/poll/poll-rtl.css b/core/modules/poll/poll.theme-rtl.css
similarity index 50%
rename from core/modules/poll/poll-rtl.css
rename to core/modules/poll/poll.theme-rtl.css
index 1d215d7..2ba85c6 100644
--- a/core/modules/poll/poll-rtl.css
+++ b/core/modules/poll/poll.theme-rtl.css
@@ -1,7 +1,9 @@
-.poll .bar .foreground {
- float: right;
-}
+/**
+ * @file
+ * Right-to-left specfic theme stylesheet for the Poll module.
+ */
+
.poll .percent {
text-align: left;
}
diff --git a/core/modules/poll/poll.theme.css b/core/modules/poll/poll.theme.css
new file mode 100644
index 0000000..3e91786
--- /dev/null
+++ b/core/modules/poll/poll.theme.css
@@ -0,0 +1,34 @@
+
+/**
+ * @file
+ * Theme stylesheet for the Poll module.
+ */
+
+.poll dl,
+.poll dd {
+ margin: 0;
+}
+.poll .links {
+ text-align: center;
+}
+.poll .percent {
+ text-align: right; /* LTR */
+}
+.poll .total {
+ text-align: center;
+}
+.poll .vote-form {
+ text-align: center;
+}
+.poll .vote-form {
+ text-align: left; /* LTR */
+}
+.poll .vote-form .poll-title {
+ font-weight: bold;
+}
+td.poll-chtext {
+ width: 80%;
+}
+td.poll-chvotes .form-text {
+ width: 85%;
+}
diff --git a/core/modules/rdf/rdf.test b/core/modules/rdf/rdf.test
index 1344ded..6c7635f 100644
--- a/core/modules/rdf/rdf.test
+++ b/core/modules/rdf/rdf.test
@@ -42,6 +42,8 @@ class RdfMappingHookTestCase extends DrupalWebTestCase {
* Test RDFa markup generation.
*/
class RdfRdfaMarkupTestCase extends DrupalWebTestCase {
+ protected $profile = 'standard';
+
public static function getInfo() {
return array(
'name' => 'RDFa markup',
@@ -123,7 +125,7 @@ class RdfRdfaMarkupTestCase extends DrupalWebTestCase {
$admin_user = $this->drupalCreateUser(array('edit own article content', 'revert revisions', 'administer content types'));
$this->drupalLogin($admin_user);
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$bundle_name = "article";
$field_name = 'file_test';
@@ -191,7 +193,7 @@ class RdfRdfaMarkupTestCase extends DrupalWebTestCase {
$tag1 = $this->randomName(8);
$tag2 = $this->randomName(8);
$edit = array();
- $edit['field_tags[' . LANGUAGE_NONE . ']'] = "$tag1, $tag2";
+ $edit['field_tags[' . LANGUAGE_NOT_SPECIFIED . ']'] = "$tag1, $tag2";
$this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
// Ensures the RDFa markup for the relationship between the node and its
// tags is correct.
@@ -277,6 +279,8 @@ class RdfCrudTestCase extends DrupalWebTestCase {
}
class RdfMappingDefinitionTestCase extends TaxonomyWebTestCase {
+ protected $profile = 'standard';
+
public static function getInfo() {
return array(
'name' => 'RDF mapping definition functionality',
@@ -573,6 +577,8 @@ class RdfCommentAttributesTestCase extends CommentHelperCase {
}
class RdfTrackerAttributesTestCase extends DrupalWebTestCase {
+ protected $profile = 'standard';
+
public static function getInfo() {
return array(
'name' => 'RDF tracker page mapping',
@@ -663,7 +669,7 @@ class RdfTrackerAttributesTestCase extends DrupalWebTestCase {
// date has been added to the tracker output after a comment is posted.
$comment = array(
'subject' => $this->randomName(),
- 'comment_body[' . LANGUAGE_NONE . '][0][value]' => $this->randomName(),
+ 'comment_body[' . LANGUAGE_NOT_SPECIFIED . '][0][value]' => $this->randomName(),
);
$this->drupalPost('comment/reply/' . $node->nid, $comment, t('Save'));
$this->drupalGet('tracker');
diff --git a/core/modules/search/search.pages.inc b/core/modules/search/search.pages.inc
index 1b7c3ef..ff0d271 100644
--- a/core/modules/search/search.pages.inc
+++ b/core/modules/search/search.pages.inc
@@ -109,7 +109,7 @@ function template_preprocess_search_result(&$variables) {
$result = $variables['result'];
$variables['url'] = check_url($result['link']);
$variables['title'] = check_plain($result['title']);
- if (isset($result['language']) && $result['language'] != $language_interface->langcode && $result['language'] != LANGUAGE_NONE) {
+ if (isset($result['language']) && $result['language'] != $language_interface->langcode && $result['language'] != LANGUAGE_NOT_SPECIFIED) {
$variables['title_attributes_array']['lang'] = $result['language'];
$variables['content_attributes_array']['lang'] = $result['language'];
}
diff --git a/core/modules/search/search.test b/core/modules/search/search.test
index 1ee4e6f..376c8e1 100644
--- a/core/modules/search/search.test
+++ b/core/modules/search/search.test
@@ -11,7 +11,26 @@ const SEARCH_TYPE = '_test_';
const SEARCH_TYPE_2 = '_test2_';
const SEARCH_TYPE_JPN = '_test3_';
-class SearchMatchTestCase extends DrupalWebTestCase {
+class SearchWebTestCase extends DrupalWebTestCase {
+ function setUp() {
+ $modules = func_get_args();
+ if (isset($modules[0]) && is_array($modules[0])) {
+ $modules = $modules[0];
+ }
+ $modules[] = 'node';
+ $modules[] = 'search';
+ $modules[] = 'dblog';
+ parent::setUp($modules);
+
+ // Create Basic page and Article node types.
+ if ($this->profile != 'standard') {
+ $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
+ $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
+ }
+ }
+}
+
+class SearchMatchTestCase extends SearchWebTestCase {
public static function getInfo() {
return array(
'name' => 'Search engine queries',
@@ -21,13 +40,6 @@ class SearchMatchTestCase extends DrupalWebTestCase {
}
/**
- * Implementation setUp().
- */
- function setUp() {
- parent::setUp('search');
- }
-
- /**
* Test search indexing.
*/
function testMatching() {
@@ -243,7 +255,7 @@ class SearchMatchTestCase extends DrupalWebTestCase {
/**
* Tests the bike shed text on no results page, and text on the search page.
*/
-class SearchPageText extends DrupalWebTestCase {
+class SearchPageText extends SearchWebTestCase {
protected $searching_user;
public static function getInfo() {
@@ -255,7 +267,7 @@ class SearchPageText extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('search');
+ parent::setUp();
// Create user.
$this->searching_user = $this->drupalCreateUser(array('search content', 'access user profiles'));
@@ -307,7 +319,7 @@ class SearchPageText extends DrupalWebTestCase {
}
}
-class SearchAdvancedSearchForm extends DrupalWebTestCase {
+class SearchAdvancedSearchForm extends SearchWebTestCase {
protected $node;
public static function getInfo() {
@@ -319,7 +331,7 @@ class SearchAdvancedSearchForm extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('search');
+ parent::setUp();
// Create and login user.
$test_user = $this->drupalCreateUser(array('access content', 'search content', 'use advanced search', 'administer nodes'));
$this->drupalLogin($test_user);
@@ -370,7 +382,7 @@ class SearchAdvancedSearchForm extends DrupalWebTestCase {
}
}
-class SearchRankingTestCase extends DrupalWebTestCase {
+class SearchRankingTestCase extends SearchWebTestCase {
public static function getInfo() {
return array(
'name' => 'Search engine ranking',
@@ -379,16 +391,13 @@ class SearchRankingTestCase extends DrupalWebTestCase {
);
}
- /**
- * Implementation setUp().
- */
function setUp() {
- parent::setUp('search', 'statistics', 'comment');
+ parent::setUp(array('statistics', 'comment'));
}
function testRankings() {
// Login with sufficient privileges.
- $this->drupalLogin($this->drupalCreateUser(array('skip comment approval', 'create page content')));
+ $this->drupalLogin($this->drupalCreateUser(array('post comments', 'skip comment approval', 'create page content')));
// Build a list of the rankings to test.
$node_ranks = array('sticky', 'promote', 'relevance', 'recent', 'comments', 'views');
@@ -398,7 +407,7 @@ class SearchRankingTestCase extends DrupalWebTestCase {
$settings = array(
'type' => 'page',
'title' => 'Drupal rocks',
- 'body' => array(LANGUAGE_NONE => array(array('value' => "Drupal's search rocks"))),
+ 'body' => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => "Drupal's search rocks"))),
);
foreach (array(0, 1) as $num) {
if ($num == 1) {
@@ -408,7 +417,7 @@ class SearchRankingTestCase extends DrupalWebTestCase {
$settings[$node_rank] = 1;
break;
case 'relevance':
- $settings['body'][LANGUAGE_NONE][0]['value'] .= " really rocks";
+ $settings['body'][LANGUAGE_NOT_SPECIFIED][0]['value'] .= " really rocks";
break;
case 'recent':
$settings['created'] = REQUEST_TIME + 3600;
@@ -432,7 +441,7 @@ class SearchRankingTestCase extends DrupalWebTestCase {
// Add a comment to one of the nodes.
$edit = array();
$edit['subject'] = 'my comment title';
- $edit['comment_body[' . LANGUAGE_NONE . '][0][value]'] = 'some random comment';
+ $edit['comment_body[' . LANGUAGE_NOT_SPECIFIED . '][0][value]'] = 'some random comment';
$this->drupalGet('comment/reply/' . $nodes['comments'][1]->nid);
$this->drupalPost(NULL, $edit, t('Preview'));
$this->drupalPost(NULL, $edit, t('Save'));
@@ -462,6 +471,13 @@ class SearchRankingTestCase extends DrupalWebTestCase {
* Test rankings of HTML tags.
*/
function testHTMLRankings() {
+ $full_html_format = array(
+ 'format' => 'full_html',
+ 'name' => 'Full HTML',
+ );
+ $full_html_format = (object) $full_html_format;
+ filter_format_save($full_html_format);
+
// Login with sufficient privileges.
$this->drupalLogin($this->drupalCreateUser(array('create page content')));
@@ -478,13 +494,13 @@ class SearchRankingTestCase extends DrupalWebTestCase {
foreach ($shuffled_tags as $tag) {
switch ($tag) {
case 'a':
- $settings['body'] = array(LANGUAGE_NONE => array(array('value' => l('Drupal Rocks', 'node'), 'format' => 'full_html')));
+ $settings['body'] = array(LANGUAGE_NOT_SPECIFIED => array(array('value' => l('Drupal Rocks', 'node'), 'format' => 'full_html')));
break;
case 'notag':
- $settings['body'] = array(LANGUAGE_NONE => array(array('value' => 'Drupal Rocks')));
+ $settings['body'] = array(LANGUAGE_NOT_SPECIFIED => array(array('value' => 'Drupal Rocks')));
break;
default:
- $settings['body'] = array(LANGUAGE_NONE => array(array('value' => "<$tag>Drupal Rocks$tag>", 'format' => 'full_html')));
+ $settings['body'] = array(LANGUAGE_NOT_SPECIFIED => array(array('value' => "<$tag>Drupal Rocks$tag>", 'format' => 'full_html')));
break;
}
$nodes[$tag] = $this->drupalCreateNode($settings);
@@ -517,7 +533,7 @@ class SearchRankingTestCase extends DrupalWebTestCase {
// Test tags with the same weight against the sorted tags.
$unsorted_tags = array('u', 'b', 'i', 'strong', 'em');
foreach ($unsorted_tags as $tag) {
- $settings['body'] = array(LANGUAGE_NONE => array(array('value' => "<$tag>Drupal Rocks$tag>", 'format' => 'full_html')));
+ $settings['body'] = array(LANGUAGE_NOT_SPECIFIED => array(array('value' => "<$tag>Drupal Rocks$tag>", 'format' => 'full_html')));
$node = $this->drupalCreateNode($settings);
// Update the search index.
@@ -553,7 +569,7 @@ class SearchRankingTestCase extends DrupalWebTestCase {
$settings = array(
'type' => 'page',
'title' => 'Drupal rocks',
- 'body' => array(LANGUAGE_NONE => array(array('value' => "Drupal's search rocks"))),
+ 'body' => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => "Drupal's search rocks"))),
'sticky' => 1,
);
@@ -580,7 +596,7 @@ class SearchRankingTestCase extends DrupalWebTestCase {
}
}
-class SearchBlockTestCase extends DrupalWebTestCase {
+class SearchBlockTestCase extends SearchWebTestCase {
public static function getInfo() {
return array(
'name' => 'Block availability',
@@ -590,7 +606,7 @@ class SearchBlockTestCase extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('search');
+ parent::setUp(array('block'));
// Create and login user
$admin_user = $this->drupalCreateUser(array('administer blocks', 'search content'));
@@ -660,7 +676,7 @@ class SearchBlockTestCase extends DrupalWebTestCase {
/**
* Tests that searching for a phrase gets the correct page count.
*/
-class SearchExactTestCase extends DrupalWebTestCase {
+class SearchExactTestCase extends SearchWebTestCase {
public static function getInfo() {
return array(
'name' => 'Search engine phrase queries',
@@ -669,10 +685,6 @@ class SearchExactTestCase extends DrupalWebTestCase {
);
}
- function setUp() {
- parent::setUp('search');
- }
-
/**
* Tests that the correct number of pager links are found for both keywords and phrases.
*/
@@ -686,12 +698,12 @@ class SearchExactTestCase extends DrupalWebTestCase {
);
// Create nodes with exact phrase.
for ($i = 0; $i <= 17; $i++) {
- $settings['body'] = array(LANGUAGE_NONE => array(array('value' => 'love pizza')));
+ $settings['body'] = array(LANGUAGE_NOT_SPECIFIED => array(array('value' => 'love pizza')));
$this->drupalCreateNode($settings);
}
// Create nodes containing keywords.
for ($i = 0; $i <= 17; $i++) {
- $settings['body'] = array(LANGUAGE_NONE => array(array('value' => 'love cheesy pizza')));
+ $settings['body'] = array(LANGUAGE_NOT_SPECIFIED => array(array('value' => 'love cheesy pizza')));
$this->drupalCreateNode($settings);
}
@@ -721,7 +733,9 @@ class SearchExactTestCase extends DrupalWebTestCase {
/**
* Test integration searching comments.
*/
-class SearchCommentTestCase extends DrupalWebTestCase {
+class SearchCommentTestCase extends SearchWebTestCase {
+ protected $profile = 'standard';
+
protected $admin_user;
public static function getInfo() {
@@ -733,7 +747,7 @@ class SearchCommentTestCase extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('comment', 'search');
+ parent::setUp(array('comment'));
// Create and log in an administrative user having access to the Full HTML
// text format.
@@ -776,9 +790,9 @@ class SearchCommentTestCase extends DrupalWebTestCase {
// Post a comment using 'Full HTML' text format.
$edit_comment = array();
$edit_comment['subject'] = 'Test comment subject';
- $edit_comment['comment_body[' . LANGUAGE_NONE . '][0][value]'] = '' . $comment_body . '
';
+ $edit_comment['comment_body[' . LANGUAGE_NOT_SPECIFIED . '][0][value]'] = '' . $comment_body . '
';
$full_html_format_id = 'full_html';
- $edit_comment['comment_body[' . LANGUAGE_NONE . '][0][format]'] = $full_html_format_id;
+ $edit_comment['comment_body[' . LANGUAGE_NOT_SPECIFIED . '][0][format]'] = $full_html_format_id;
$this->drupalPost('comment/reply/' . $node->nid, $edit_comment, t('Save'));
// Invoke search index update.
@@ -803,7 +817,7 @@ class SearchCommentTestCase extends DrupalWebTestCase {
// Verify that comment is rendered using proper format.
$this->assertText($comment_body, t('Comment body text found in search results.'));
$this->assertNoRaw(t('n/a'), t('HTML in comment body is not hidden.'));
- $this->assertNoRaw(check_plain($edit_comment['comment_body[' . LANGUAGE_NONE . '][0][value]']), t('HTML in comment body is not escaped.'));
+ $this->assertNoRaw(check_plain($edit_comment['comment_body[' . LANGUAGE_NOT_SPECIFIED . '][0][value]']), t('HTML in comment body is not escaped.'));
// Hide comments.
$this->drupalLogin($this->admin_user);
@@ -836,7 +850,7 @@ class SearchCommentTestCase extends DrupalWebTestCase {
// Post a comment using 'Full HTML' text format.
$edit_comment = array();
$edit_comment['subject'] = $this->comment_subject;
- $edit_comment['comment_body[' . LANGUAGE_NONE . '][0][value]'] = '' . $comment_body . '
';
+ $edit_comment['comment_body[' . LANGUAGE_NOT_SPECIFIED . '][0][value]'] = '' . $comment_body . '
';
$this->drupalPost('comment/reply/' . $this->node->nid, $edit_comment, t('Save'));
$this->drupalLogout();
@@ -916,7 +930,7 @@ class SearchCommentTestCase extends DrupalWebTestCase {
$settings = array(
'type' => 'article',
'title' => 'short title',
- 'body' => array(LANGUAGE_NONE => array(array('value' => 'short body text'))),
+ 'body' => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => 'short body text'))),
);
$user = $this->drupalCreateUser(array('search content', 'create article content', 'access content'));
@@ -1017,7 +1031,10 @@ class SearchExpressionInsertExtractTestCase extends DrupalUnitTestCase {
* only when there are comments
* - Nodes with comment status set to Hidden should never show comment counts
*/
-class SearchCommentCountToggleTestCase extends DrupalWebTestCase {
+class SearchCommentCountToggleTestCase extends SearchWebTestCase {
+ // Requires node types, comment config, filter formats.
+ protected $profile = 'standard';
+
protected $searching_user;
protected $searchable_nodes;
@@ -1030,13 +1047,13 @@ class SearchCommentCountToggleTestCase extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('search');
+ parent::setUp(array('comment'));
// Create searching user.
$this->searching_user = $this->drupalCreateUser(array('search content', 'access content', 'access comments', 'skip comment approval'));
// Create initial nodes.
- $node_params = array('type' => 'article', 'body' => array(LANGUAGE_NONE => array(array('value' => 'SearchCommentToggleTestCase'))));
+ $node_params = array('type' => 'article', 'body' => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => 'SearchCommentToggleTestCase'))));
$this->searchable_nodes['1 comment'] = $this->drupalCreateNode($node_params);
$this->searchable_nodes['0 comments'] = $this->drupalCreateNode($node_params);
@@ -1047,9 +1064,9 @@ class SearchCommentCountToggleTestCase extends DrupalWebTestCase {
// Create a comment array
$edit_comment = array();
$edit_comment['subject'] = $this->randomName();
- $edit_comment['comment_body[' . LANGUAGE_NONE . '][0][value]'] = $this->randomName();
+ $edit_comment['comment_body[' . LANGUAGE_NOT_SPECIFIED . '][0][value]'] = $this->randomName();
$filtered_html_format_id = 'filtered_html';
- $edit_comment['comment_body[' . LANGUAGE_NONE . '][0][format]'] = $filtered_html_format_id;
+ $edit_comment['comment_body[' . LANGUAGE_NOT_SPECIFIED . '][0][format]'] = $filtered_html_format_id;
// Post comment to the test node with comment
$this->drupalPost('comment/reply/' . $this->searchable_nodes['1 comment']->nid, $edit_comment, t('Save'));
@@ -1102,7 +1119,7 @@ class SearchCommentCountToggleTestCase extends DrupalWebTestCase {
/**
* Test search_simplify() on every Unicode character, and some other cases.
*/
-class SearchSimplifyTestCase extends DrupalWebTestCase {
+class SearchSimplifyTestCase extends SearchWebTestCase {
public static function getInfo() {
return array(
'name' => 'Search simplify',
@@ -1185,8 +1202,7 @@ class SearchSimplifyTestCase extends DrupalWebTestCase {
/**
* Tests keywords and conditions.
*/
-class SearchKeywordsConditions extends DrupalWebTestCase {
-
+class SearchKeywordsConditions extends SearchWebTestCase {
public static function getInfo() {
return array(
'name' => 'Keywords and conditions',
@@ -1196,7 +1212,7 @@ class SearchKeywordsConditions extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('search', 'search_extra_type');
+ parent::setUp(array('comment', 'search_extra_type'));
// Create searching user.
$this->searching_user = $this->drupalCreateUser(array('search content', 'access content', 'access comments', 'skip comment approval'));
// Login with sufficient privileges.
@@ -1236,7 +1252,7 @@ class SearchKeywordsConditions extends DrupalWebTestCase {
/**
* Tests that numbers can be searched.
*/
-class SearchNumbersTestCase extends DrupalWebTestCase {
+class SearchNumbersTestCase extends SearchWebTestCase {
protected $test_user;
protected $numbers;
protected $nodes;
@@ -1250,7 +1266,7 @@ class SearchNumbersTestCase extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('search');
+ parent::setUp();
$this->test_user = $this->drupalCreateUser(array('search content', 'access content', 'administer nodes', 'access site reports'));
$this->drupalLogin($this->test_user);
@@ -1277,9 +1293,9 @@ class SearchNumbersTestCase extends DrupalWebTestCase {
foreach ($this->numbers as $doc => $num) {
$info = array(
- 'body' => array(LANGUAGE_NONE => array(array('value' => $num))),
+ 'body' => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => $num))),
'type' => 'page',
- 'language' => LANGUAGE_NONE,
+ 'language' => LANGUAGE_NOT_SPECIFIED,
'title' => $doc . ' number',
);
$this->nodes[$doc] = $this->drupalCreateNode($info);
@@ -1324,7 +1340,7 @@ class SearchNumbersTestCase extends DrupalWebTestCase {
/**
* Tests that numbers can be searched, with more complex matching.
*/
-class SearchNumberMatchingTestCase extends DrupalWebTestCase {
+class SearchNumberMatchingTestCase extends SearchWebTestCase {
protected $test_user;
protected $numbers;
protected $nodes;
@@ -1338,7 +1354,7 @@ class SearchNumberMatchingTestCase extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('search');
+ parent::setUp();
$this->test_user = $this->drupalCreateUser(array('search content', 'access content', 'administer nodes', 'access site reports'));
$this->drupalLogin($this->test_user);
@@ -1359,9 +1375,9 @@ class SearchNumberMatchingTestCase extends DrupalWebTestCase {
foreach ($this->numbers as $num) {
$info = array(
- 'body' => array(LANGUAGE_NONE => array(array('value' => $num))),
+ 'body' => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => $num))),
'type' => 'page',
- 'language' => LANGUAGE_NONE,
+ 'language' => LANGUAGE_NOT_SPECIFIED,
);
$this->nodes[] = $this->drupalCreateNode($info);
}
@@ -1407,7 +1423,7 @@ class SearchNumberMatchingTestCase extends DrupalWebTestCase {
/**
* Test config page.
*/
-class SearchConfigSettingsForm extends DrupalWebTestCase {
+class SearchConfigSettingsForm extends SearchWebTestCase {
public $search_user;
public $search_node;
@@ -1420,7 +1436,7 @@ class SearchConfigSettingsForm extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('search', 'search_extra_type');
+ parent::setUp(array('block', 'search_extra_type'));
// Login as a user that can create and search content.
$this->search_user = $this->drupalCreateUser(array('search content', 'administer search', 'administer nodes', 'bypass node access', 'access user profiles', 'administer users', 'administer blocks'));
@@ -1431,7 +1447,7 @@ class SearchConfigSettingsForm extends DrupalWebTestCase {
$this->search_node = $node;
// Link the node to itself to test that it's only indexed once. The content
// also needs the word "pizza" so we can use it as the search keyword.
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$body_key = "body[$langcode][0][value]";
$edit[$body_key] = l($node->title, 'node/' . $node->nid) . ' pizza sandwich';
$this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
@@ -1645,7 +1661,7 @@ class SearchExcerptTestCase extends DrupalUnitTestCase {
/**
* Test the CJK tokenizer.
*/
-class SearchTokenizerTestCase extends DrupalWebTestCase {
+class SearchTokenizerTestCase extends SearchWebTestCase {
public static function getInfo() {
return array(
'name' => 'CJK tokenizer',
@@ -1654,10 +1670,6 @@ class SearchTokenizerTestCase extends DrupalWebTestCase {
);
}
- function setUp() {
- parent::setUp('search');
- }
-
/**
* Verifies that strings of CJK characters are tokenized.
*
@@ -1796,7 +1808,7 @@ class SearchTokenizerTestCase extends DrupalWebTestCase {
/**
* Tests that we can embed a form in search results and submit it.
*/
-class SearchEmbedForm extends DrupalWebTestCase {
+class SearchEmbedForm extends SearchWebTestCase {
/**
* Node used for testing.
*/
@@ -1816,7 +1828,7 @@ class SearchEmbedForm extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('search', 'search_embedded_form');
+ parent::setUp(array('search_embedded_form'));
// Create a user and a node, and update the search index.
$test_user = $this->drupalCreateUser(array('access content', 'search content', 'administer nodes'));
@@ -1872,7 +1884,7 @@ class SearchEmbedForm extends DrupalWebTestCase {
/**
* Tests that hook_search_page runs.
*/
-class SearchPageOverride extends DrupalWebTestCase {
+class SearchPageOverride extends SearchWebTestCase {
public $search_user;
public static function getInfo() {
@@ -1884,7 +1896,7 @@ class SearchPageOverride extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('search', 'search_extra_type');
+ parent::setUp(array('search_extra_type'));
// Login as a user that can create and search content.
$this->search_user = $this->drupalCreateUser(array('search content', 'administer search'));
@@ -1906,7 +1918,7 @@ class SearchPageOverride extends DrupalWebTestCase {
/**
* Test node search with multiple languages.
*/
-class SearchLanguageTestCase extends DrupalWebTestCase {
+class SearchLanguageTestCase extends SearchWebTestCase {
public static function getInfo() {
return array(
'name' => 'Search language selection',
@@ -1915,11 +1927,8 @@ class SearchLanguageTestCase extends DrupalWebTestCase {
);
}
- /**
- * Implementation setUp().
- */
function setUp() {
- parent::setUp('search', 'locale');
+ parent::setUp(array('locale'));
// Create and login user.
$test_user = $this->drupalCreateUser(array('access content', 'search content', 'use advanced search', 'administer nodes', 'administer languages', 'access administration pages'));
@@ -1934,7 +1943,7 @@ class SearchLanguageTestCase extends DrupalWebTestCase {
// Add predefined language.
$edit = array('predefined_langcode' => 'fr');
$this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
- $this->assertText('fr', t('Language added successfully.'));
+ $this->assertText('French', t('Language added successfully.'));
// Now we should have languages displayed.
$this->drupalGet('search/node');
@@ -1971,7 +1980,7 @@ class SearchLanguageTestCase extends DrupalWebTestCase {
/**
* Tests node search with node access control.
*/
-class SearchNodeAccessTest extends DrupalWebTestCase {
+class SearchNodeAccessTest extends SearchWebTestCase {
public $test_user;
public static function getInfo() {
@@ -1983,7 +1992,7 @@ class SearchNodeAccessTest extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('search', 'node_access_test');
+ parent::setUp(array('node_access_test'));
node_access_rebuild();
// Create a test user and log in.
@@ -1995,7 +2004,7 @@ class SearchNodeAccessTest extends DrupalWebTestCase {
* Tests that search returns results with punctuation in the search phrase.
*/
function testPhraseSearchPunctuation() {
- $node = $this->drupalCreateNode(array('body' => array(LANGUAGE_NONE => array(array('value' => "The bunny's ears were fuzzy.")))));
+ $node = $this->drupalCreateNode(array('body' => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => "The bunny's ears were fluffy.")))));
// Update the search index.
module_invoke_all('update_index');
diff --git a/core/modules/shortcut/shortcut.install b/core/modules/shortcut/shortcut.install
index 7aee9c9..60c113a 100644
--- a/core/modules/shortcut/shortcut.install
+++ b/core/modules/shortcut/shortcut.install
@@ -30,7 +30,12 @@ function shortcut_install() {
// set, to make sure the links defined above can be correctly saved. (During
// installation, the menu might not have been built at all yet, or it might
// have been built but without the node module's links in it.)
- if (drupal_installation_attempted()) {
+ // drupal_installation_attempted() cannot be used here, as it relies on the
+ // MAINTENANCE_MODE constant value, which cannot be set when running tests, so
+ // we check the 'install_task' variable instead, which is only "done" when
+ // Drupal is already installed (i.e., we are not in the installer).
+ // @see http://drupal.org/node/1376150
+ if (variable_get('install_task', '') != 'done') {
menu_rebuild();
}
shortcut_set_save($shortcut_set);
diff --git a/core/modules/shortcut/shortcut.test b/core/modules/shortcut/shortcut.test
index 322c63f..550c10c 100644
--- a/core/modules/shortcut/shortcut.test
+++ b/core/modules/shortcut/shortcut.test
@@ -32,6 +32,13 @@ class ShortcutTestCase extends DrupalWebTestCase {
function setUp() {
parent::setUp('toolbar', 'shortcut');
+
+ // Create Basic page and Article node types.
+ if ($this->profile != 'standard') {
+ $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
+ $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
+ }
+
// Create users.
$this->admin_user = $this->drupalCreateUser(array('access toolbar', 'administer shortcuts', 'view the administration theme', 'create article content', 'create page content', 'access content overview'));
$this->shortcut_user = $this->drupalCreateUser(array('customize shortcut links', 'switch shortcut sets'));
@@ -150,6 +157,9 @@ class ShortcutLinksTestCase extends ShortcutTestCase {
* Tests that the "add to shortcut" link changes to "remove shortcut".
*/
function testShortcutQuickLink() {
+ theme_enable(array('seven'));
+ variable_set('admin_theme', 'seven');
+ variable_set('node_admin_theme', TRUE);
$this->drupalGet($this->set->links[0]['link_path']);
$this->assertRaw(t('Remove from %title shortcuts', array('%title' => $this->set->title)), '"Add to shortcuts" link properly switched to "Remove from shortcuts".');
}
diff --git a/core/modules/simpletest/drupal_web_test_case.php b/core/modules/simpletest/drupal_web_test_case.php
index e5d36c3..ded4ad0 100644
--- a/core/modules/simpletest/drupal_web_test_case.php
+++ b/core/modules/simpletest/drupal_web_test_case.php
@@ -768,7 +768,7 @@ class DrupalWebTestCase extends DrupalTestCase {
*
* @var string
*/
- protected $profile = 'standard';
+ protected $profile = 'testing';
/**
* The URL currently loaded in the internal browser.
@@ -923,7 +923,7 @@ class DrupalWebTestCase extends DrupalTestCase {
protected function drupalCreateNode($settings = array()) {
// Populate defaults array.
$settings += array(
- 'body' => array(LANGUAGE_NONE => array(array())),
+ 'body' => array(LANGUAGE_NOT_SPECIFIED => array(array())),
'title' => $this->randomName(8),
'comment' => 2,
'changed' => REQUEST_TIME,
@@ -935,7 +935,7 @@ class DrupalWebTestCase extends DrupalTestCase {
'sticky' => 0,
'type' => 'page',
'revisions' => NULL,
- 'langcode' => LANGUAGE_NONE,
+ 'langcode' => LANGUAGE_NOT_SPECIFIED,
);
// Use the original node's created time for existing nodes.
@@ -1313,6 +1313,8 @@ class DrupalWebTestCase extends DrupalTestCase {
// Store necessary current values before switching to prefixed database.
$this->originalLanguage = $language_interface;
$this->originalLanguageDefault = variable_get('language_default');
+ $this->originalConfigDirectory = $GLOBALS['config_directory_name'];
+ $this->originalConfigSignatureKey = $GLOBALS['config_signature_key'];
$this->originalFileDirectory = variable_get('file_public_path', conf_path() . '/files');
$this->originalProfile = drupal_get_profile();
$clean_url_original = variable_get('clean_url', 0);
@@ -1349,6 +1351,14 @@ class DrupalWebTestCase extends DrupalTestCase {
file_prepare_directory($temp_files_directory, FILE_CREATE_DIRECTORY);
$this->generatedTestFiles = FALSE;
+ // Create and set a new configuration directory and signature key.
+ // The child site automatically adjusts the global $config_directory_name to
+ // a test-prefix-specific directory within the public files directory.
+ $GLOBALS['config_directory_name'] = 'simpletest/config_' . $this->databasePrefix;
+ $this->configFileDirectory = $this->originalFileDirectory . '/' . $GLOBALS['config_directory_name'];
+ file_prepare_directory($this->configFileDirectory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
+ $GLOBALS['config_signature_key'] = drupal_hash_base64(drupal_random_bytes(55));
+
// Log fatal errors.
ini_set('log_errors', 1);
ini_set('error_log', $public_files_directory . '/error.log');
@@ -1431,7 +1441,7 @@ class DrupalWebTestCase extends DrupalTestCase {
$language_interface = language_default();
// Use the test mail class instead of the default mail handler class.
- variable_set('mail_system', array('default-system' => 'TestingMailSystem'));
+ variable_set('mail_system', array('default-system' => 'Drupal\Core\Mail\VariableLog'));
drupal_set_time_limit($this->timeLimit);
$this->setup = TRUE;
@@ -1571,6 +1581,10 @@ class DrupalWebTestCase extends DrupalTestCase {
// Rebuild caches.
$this->refreshVariables();
+ // Reset configuration globals.
+ $GLOBALS['config_directory_name'] = $this->originalConfigDirectory;
+ $GLOBALS['config_signature_key'] = $this->originalConfigSignatureKey;
+
// Reset language.
$language_interface = $this->originalLanguage;
if ($this->originalLanguageDefault) {
@@ -2248,8 +2262,10 @@ class DrupalWebTestCase extends DrupalTestCase {
case 'text':
case 'tel':
case 'textarea':
+ case 'url':
case 'hidden':
case 'password':
+ case 'email':
$post[$name] = $edit[$name];
unset($edit[$name]);
break;
diff --git a/core/modules/simpletest/simpletest.info b/core/modules/simpletest/simpletest.info
index d518a76..cf55121 100644
--- a/core/modules/simpletest/simpletest.info
+++ b/core/modules/simpletest/simpletest.info
@@ -29,6 +29,7 @@ files[] = tests/module.test
files[] = tests/pager.test
files[] = tests/password.test
files[] = tests/path.test
+files[] = tests/queue.test
files[] = tests/registry.test
files[] = tests/schema.test
files[] = tests/session.test
@@ -37,6 +38,7 @@ files[] = tests/tablesort.test
files[] = tests/theme.test
files[] = tests/unicode.test
files[] = tests/update.test
+files[] = tests/uuid.test
files[] = tests/xmlrpc.test
files[] = tests/upgrade/upgrade.test
files[] = tests/upgrade/upgrade_bare.test
diff --git a/core/modules/simpletest/simpletest.test b/core/modules/simpletest/simpletest.test
index f4bdd13..55a48be 100644
--- a/core/modules/simpletest/simpletest.test
+++ b/core/modules/simpletest/simpletest.test
@@ -72,7 +72,9 @@ class SimpleTestFunctionalTest extends DrupalWebTestCase {
'pass' => $user->pass_raw
);
variable_set('simpletest_maximum_redirects', 1);
- $this->drupalPost('user?destination=user/logout', $edit, t('Log in'));
+ $this->drupalPost('user', $edit, t('Log in'), array(
+ 'query' => array('destination' => 'user/logout'),
+ ));
$headers = $this->drupalGetHeaders(TRUE);
$this->assertEqual(count($headers), 2, t('Simpletest stopped following redirects after the first one.'));
}
diff --git a/core/modules/simpletest/tests/ajax.test b/core/modules/simpletest/tests/ajax.test
index 014a350..3184add 100644
--- a/core/modules/simpletest/tests/ajax.test
+++ b/core/modules/simpletest/tests/ajax.test
@@ -58,8 +58,6 @@ class AJAXTestCase extends DrupalWebTestCase {
* Tests primary Ajax framework functions.
*/
class AJAXFrameworkTestCase extends AJAXTestCase {
- protected $profile = 'testing';
-
public static function getInfo() {
return array(
'name' => 'AJAX framework',
@@ -426,6 +424,8 @@ class AJAXFormValuesTestCase extends AJAXTestCase {
* Tests that Ajax-enabled forms work when multiple instances of the same form are on a page.
*/
class AJAXMultiFormTestCase extends AJAXTestCase {
+ protected $profile = 'standard';
+
public static function getInfo() {
return array(
'name' => 'AJAX multi form',
diff --git a/core/modules/simpletest/tests/bootstrap.test b/core/modules/simpletest/tests/bootstrap.test
index 13fdf07..371031a 100644
--- a/core/modules/simpletest/tests/bootstrap.test
+++ b/core/modules/simpletest/tests/bootstrap.test
@@ -109,14 +109,19 @@ class BootstrapPageCacheTestCase extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('system_test');
+ parent::setUp(array('node', 'system_test'));
+
+ variable_set('site_name', 'Drupal');
+ variable_set('site_frontpage', 'node');
}
/**
* Test support for requests containing If-Modified-Since and If-None-Match headers.
*/
function testConditionalRequests() {
- variable_set('cache', 1);
+ $config = config('system.performance');
+ $config->set('cache', 1);
+ $config->save();
// Fill the cache.
$this->drupalGet('');
@@ -154,7 +159,9 @@ class BootstrapPageCacheTestCase extends DrupalWebTestCase {
* Test cache headers.
*/
function testPageCache() {
- variable_set('cache', 1);
+ $config = config('system.performance');
+ $config->set('cache', 1);
+ $config->save();
// Fill the cache.
$this->drupalGet('system-test/set-header', array('query' => array('name' => 'Foo', 'value' => 'bar')));
@@ -198,7 +205,9 @@ class BootstrapPageCacheTestCase extends DrupalWebTestCase {
* mod_deflate Apache module.
*/
function testPageCompression() {
- variable_set('cache', 1);
+ $config = config('system.performance');
+ $config->set('cache', 1);
+ $config->save();
// Fill the cache and verify that output is compressed.
$this->drupalGet('', array(), array('Accept-Encoding: gzip,deflate'));
@@ -291,14 +300,18 @@ class HookBootExitTestCase extends DrupalWebTestCase {
*/
function testHookBootExit() {
// Test with cache disabled. Boot and exit should always fire.
- variable_set('cache', 0);
+ $config = config('system.performance');
+ $config->set('cache', 0);
+ $config->save();
+
$this->drupalGet('');
$calls = 1;
$this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_boot'))->fetchField(), $calls, t('hook_boot called with disabled cache.'));
$this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_exit'))->fetchField(), $calls, t('hook_exit called with disabled cache.'));
// Test with normal cache. Boot and exit should be called.
- variable_set('cache', 1);
+ $config->set('cache', 1);
+ $config->save();
$this->drupalGet('');
$calls++;
$this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_boot'))->fetchField(), $calls, t('hook_boot called with normal cache.'));
diff --git a/core/modules/simpletest/tests/cache.test b/core/modules/simpletest/tests/cache.test
index bca4e25..81f2377 100644
--- a/core/modules/simpletest/tests/cache.test
+++ b/core/modules/simpletest/tests/cache.test
@@ -95,7 +95,9 @@ class CacheTestCase extends DrupalWebTestCase {
* The time in seconds the cache should minimal live.
*/
protected function setupLifetime($time) {
- variable_set('cache_lifetime', $time);
+ $config = config('system.performance');
+ $config->set('cache_lifetime', $time);
+ $config->save();
variable_set('cache_flush', 0);
}
}
diff --git a/core/modules/simpletest/tests/common.test b/core/modules/simpletest/tests/common.test
index 30449b6..4f20361 100644
--- a/core/modules/simpletest/tests/common.test
+++ b/core/modules/simpletest/tests/common.test
@@ -18,7 +18,7 @@ class CommonDrupalAlterTestCase extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('common_test');
+ parent::setUp(array('block', 'common_test'));
}
function testDrupalAlter() {
@@ -594,7 +594,7 @@ class CommonCascadingStylesheetsTestCase extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('php', 'language', 'common_test');
+ parent::setUp(array('language', 'common_test'));
// Reset drupal_add_css() before each test.
drupal_static_reset('drupal_add_css');
}
@@ -700,17 +700,22 @@ class CommonCascadingStylesheetsTestCase extends DrupalWebTestCase {
* Tests rendering inline stylesheets through a full page request.
*/
function testRenderInlineFullPage() {
+ module_enable(array('php'));
+
$css = 'body { font-size: 254px; }';
// Inline CSS is minified unless 'preprocess' => FALSE is passed as a
// drupal_add_css() option.
$expected = 'body{font-size:254px;}';
+ // Create Basic page node type.
+ $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
+
// Create a node, using the PHP filter that tests drupal_add_css().
$php_format_id = 'php_code';
$settings = array(
'type' => 'page',
'body' => array(
- LANGUAGE_NONE => array(
+ LANGUAGE_NOT_SPECIFIED => array(
array(
'value' => t('This tests the inline CSS!') . "",
'format' => $php_format_id,
@@ -1191,8 +1196,10 @@ class CommonJavaScriptTestCase extends DrupalWebTestCase {
parent::setUp('locale', 'simpletest', 'common_test');
// Disable preprocessing
- $this->preprocess_js = variable_get('preprocess_js', 0);
- variable_set('preprocess_js', 0);
+ $config = config('system.performance');
+ $this->preprocess_js = $config->get('preprocess_js');
+ $config->set('preprocess_js', 0);
+ $config->save();
// Reset drupal_add_js() and drupal_add_library() statics before each test.
drupal_static_reset('drupal_add_js');
@@ -1201,7 +1208,9 @@ class CommonJavaScriptTestCase extends DrupalWebTestCase {
function tearDown() {
// Restore configured value for JavaScript preprocessing.
- variable_set('preprocess_js', $this->preprocess_js);
+ $config = config('system.performance');
+ $config->set('preprocess_js', $this->preprocess_js);
+ $config->save();
parent::tearDown();
}
@@ -1399,7 +1408,9 @@ class CommonJavaScriptTestCase extends DrupalWebTestCase {
// Now ensure that with aggregation on, one file is made for the
// 'every_page' files, and one file is made for the others.
drupal_static_reset('drupal_add_js');
- variable_set('preprocess_js', 1);
+ $config = config('system.performance');
+ $config->set('preprocess_js', 1);
+ $config->save();
drupal_add_js('core/misc/ajax.js');
drupal_add_js('core/misc/authorize.js', array('every_page' => TRUE));
drupal_add_js('core/misc/autocomplete.js');
@@ -2249,11 +2260,6 @@ class CommonDrupalParseInfoFileTestCase extends DrupalUnitTestCase {
* Tests scanning system directories in drupal_system_listing().
*/
class CommonDrupalSystemListingTestCase extends DrupalWebTestCase {
- /**
- * Use the testing profile; this is needed for testDirectoryPrecedence().
- */
- protected $profile = 'testing';
-
public static function getInfo() {
return array(
'name' => 'Drupal system listing',
@@ -2394,7 +2400,7 @@ class CommonFormatDateTestCase extends DrupalWebTestCase {
// Create a test user to carry out the tests.
$test_user = $this->drupalCreateUser();
$this->drupalLogin($test_user);
- $edit = array('language' => self::LANGCODE, 'mail' => $test_user->mail, 'timezone' => 'America/Los_Angeles');
+ $edit = array('preferred_langcode' => self::LANGCODE, 'mail' => $test_user->mail, 'timezone' => 'America/Los_Angeles');
$this->drupalPost('user/' . $test_user->uid . '/edit', $edit, t('Save'));
// Disable session saving as we are about to modify the global $user.
@@ -2403,7 +2409,7 @@ class CommonFormatDateTestCase extends DrupalWebTestCase {
$real_user = $user;
$user = user_load($test_user->uid, TRUE);
$real_language = $language_interface->langcode;
- $language_interface->langcode = $user->language;
+ $language_interface->langcode = $user->preferred_langcode;
// Simulate a Drupal bootstrap with the logged-in user.
date_default_timezone_set(drupal_get_user_timezone());
diff --git a/core/modules/simpletest/tests/database_test.test b/core/modules/simpletest/tests/database_test.test
index 1d38ebb..487953e 100644
--- a/core/modules/simpletest/tests/database_test.test
+++ b/core/modules/simpletest/tests/database_test.test
@@ -25,8 +25,6 @@ class FakeRecord { }
* here.
*/
class DatabaseTestCase extends DrupalWebTestCase {
- protected $profile = 'testing';
-
function setUp() {
$modules = func_get_args();
if (isset($modules[0]) && is_array($modules[0])) {
diff --git a/core/modules/simpletest/tests/file.test b/core/modules/simpletest/tests/file.test
index a369a44..5b6a6f4 100644
--- a/core/modules/simpletest/tests/file.test
+++ b/core/modules/simpletest/tests/file.test
@@ -47,6 +47,20 @@ function file_test_file_scan_callback_reset() {
* assertions and helper functions.
*/
class FileTestCase extends DrupalWebTestCase {
+
+ function setUp() {
+ $modules = func_get_args();
+ $modules = (isset($modules[0]) && is_array($modules[0]) ? $modules[0] : $modules);
+ parent::setUp($modules);
+
+ // Make sure that custom stream wrappers are registered.
+ // @todo This has the potential to be a major bug deeply buried in File API;
+ // file_unmanaged_*() API functions and test functions are invoking native
+ // PHP functions directly, whereas Drupal's custom stream wrappers are not
+ // registered yet.
+ file_get_stream_wrappers();
+ }
+
/**
* Check that two files have the same values for all fields other than the
* timestamp.
@@ -2011,11 +2025,12 @@ class FileSaveTest extends FileHookTestCase {
$this->assertEqual($loaded_file->status, $file->status, t("Status was saved correctly."));
$this->assertEqual($saved_file->filesize, filesize($file->uri), t("File size was set correctly."), 'File');
$this->assertTrue($saved_file->timestamp > 1, t("File size was set correctly."), 'File');
-
+ $this->assertEqual($loaded_file->langcode, LANGUAGE_NOT_SPECIFIED, t("Langcode was defaulted correctly."));
// Resave the file, updating the existing record.
file_test_reset();
$saved_file->status = 7;
+ $saved_file->langcode = 'en';
$resaved_file = file_save($saved_file);
// Check that the correct hooks were called.
@@ -2026,6 +2041,7 @@ class FileSaveTest extends FileHookTestCase {
$loaded_file = db_query('SELECT * FROM {file_managed} f WHERE f.fid = :fid', array(':fid' => $saved_file->fid))->fetch(PDO::FETCH_OBJ);
$this->assertNotNull($loaded_file, t("Record still exists in the database."), 'File');
$this->assertEqual($loaded_file->status, $saved_file->status, t("Status was saved correctly."));
+ $this->assertEqual($loaded_file->langcode, 'en', t("Langcode was saved correctly."));
}
}
@@ -2712,7 +2728,7 @@ class StreamWrapperTest extends DrupalWebTestCase {
// Check the dummy scheme.
$this->assertEqual($this->classname, file_stream_wrapper_get_class($this->scheme), t('Got correct class name for dummy scheme.'));
// Check core's scheme.
- $this->assertEqual('DrupalPublicStreamWrapper', file_stream_wrapper_get_class('public'), t('Got correct class name for public scheme.'));
+ $this->assertEqual('Drupal\Core\StreamWrapper\PublicStream', file_stream_wrapper_get_class('public'), t('Got correct class name for public scheme.'));
}
/**
@@ -2723,7 +2739,7 @@ class StreamWrapperTest extends DrupalWebTestCase {
$this->assertEqual($this->classname, get_class($instance), t('Got correct class type for dummy scheme.'));
$instance = file_stream_wrapper_get_instance_by_scheme('public');
- $this->assertEqual('DrupalPublicStreamWrapper', get_class($instance), t('Got correct class type for public scheme.'));
+ $this->assertEqual('Drupal\Core\StreamWrapper\PublicStream', get_class($instance), t('Got correct class type for public scheme.'));
}
/**
@@ -2734,13 +2750,14 @@ class StreamWrapperTest extends DrupalWebTestCase {
$this->assertEqual($this->classname, get_class($instance), t('Got correct class type for dummy URI.'));
$instance = file_stream_wrapper_get_instance_by_uri('public://foo');
- $this->assertEqual('DrupalPublicStreamWrapper', get_class($instance), t('Got correct class type for public URI.'));
+ $this->assertEqual('Drupal\Core\StreamWrapper\PublicStream', get_class($instance), t('Got correct class type for public URI.'));
// Test file_uri_target().
$this->assertEqual(file_uri_target('public://foo/bar.txt'), 'foo/bar.txt', t('Got a valid stream target from public://foo/bar.txt.'));
$this->assertFalse(file_uri_target('foo/bar.txt'), t('foo/bar.txt is not a valid stream.'));
- // Test file_build_uri() and DrupalLocalStreamWrapper::getDirectoryPath().
+ // Test file_build_uri() and
+ // Drupal\Core\StreamWrapper\LocalStream::getDirectoryPath().
$this->assertEqual(file_build_uri('foo/bar.txt'), 'public://foo/bar.txt', t('Expected scheme was added.'));
$this->assertEqual(file_stream_wrapper_get_instance_by_scheme('public')->getDirectoryPath(), variable_get('file_public_path'), t('Expected default directory path was returned.'));
$this->assertEqual(file_stream_wrapper_get_instance_by_scheme('temporary')->getDirectoryPath(), variable_get('file_temporary_path'), t('Expected temporary directory path was returned.'));
diff --git a/core/modules/simpletest/tests/file_test.module b/core/modules/simpletest/tests/file_test.module
index 6fcda95..8a9a84a 100644
--- a/core/modules/simpletest/tests/file_test.module
+++ b/core/modules/simpletest/tests/file_test.module
@@ -8,6 +8,8 @@
* calling file_test_get_calls() or file_test_set_return().
*/
+use Drupal\Core\StreamWrapper\LocalStream;
+use Drupal\Core\StreamWrapper\PublicStream;
const FILE_URL_TEST_CDN_1 = 'http://cdn1.example.com';
const FILE_URL_TEST_CDN_2 = 'http://cdn2.example.com';
@@ -423,7 +425,7 @@ function file_test_file_mimetype_mapping_alter(&$mapping) {
*
* Dummy stream wrapper implementation (dummy://).
*/
-class DrupalDummyStreamWrapper extends DrupalLocalStreamWrapper {
+class DrupalDummyStreamWrapper extends LocalStream {
function getDirectoryPath() {
return variable_get('stream_public_path', 'sites/default/files');
}
@@ -454,7 +456,7 @@ class DrupalDummyStreamWrapper extends DrupalLocalStreamWrapper {
*
* Basically just the public scheme but not returning a local file for realpath.
*/
-class DrupalDummyRemoteStreamWrapper extends DrupalPublicStreamWrapper {
+class DrupalDummyRemoteStreamWrapper extends PublicStream {
function realpath() {
return FALSE;
}
diff --git a/core/modules/simpletest/tests/form.test b/core/modules/simpletest/tests/form.test
index 6e40f1f..3946374 100644
--- a/core/modules/simpletest/tests/form.test
+++ b/core/modules/simpletest/tests/form.test
@@ -16,7 +16,17 @@ class FormsTestCase extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('form_test');
+ parent::setUp(array('form_test', 'file'));
+
+ $filtered_html_format = array(
+ 'format' => 'filtered_html',
+ 'name' => 'Filtered HTML',
+ );
+ $filtered_html_format = (object) $filtered_html_format;
+ filter_format_save($filtered_html_format);
+
+ $filtered_html_permission = filter_permission_name($filtered_html_format);
+ user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array($filtered_html_permission));
}
/**
@@ -40,6 +50,9 @@ class FormsTestCase extends DrupalWebTestCase {
$elements['telephone']['element'] = array('#title' => $this->randomName(), '#type' => 'tel');
$elements['telephone']['empty_values'] = $empty_strings;
+ $elements['url']['element'] = array('#title' => $this->randomName(), '#type' => 'url');
+ $elements['url']['empty_values'] = $empty_strings;
+
$elements['password']['element'] = array('#title' => $this->randomName(), '#type' => 'password');
$elements['password']['empty_values'] = $empty_strings;
@@ -125,6 +138,72 @@ class FormsTestCase extends DrupalWebTestCase {
}
/**
+ * Tests validation for required checkbox, select, and radio elements.
+ *
+ * Submits a test form containing several types of form elements. The form
+ * is submitted twice, first without values for required fields and then
+ * with values. Each submission is checked for relevant error messages.
+ *
+ * @see form_test_validate_required_form()
+ */
+ function testRequiredCheckboxesRadio() {
+ $form = $form_state = array();
+ $form = form_test_validate_required_form($form, $form_state);
+
+ // Attempt to submit the form with no required fields set.
+ $edit = array();
+ $this->drupalPost('form-test/validate-required', $edit, 'Submit');
+
+ // The only error messages that should appear are the relevant 'required'
+ // messages for each field.
+ $expected = array();
+ foreach (array('textfield', 'checkboxes', 'select', 'radios') as $key) {
+ $expected[] = t('!name field is required.', array('!name' => $form[$key]['#title']));
+ }
+
+ // Check the page for error messages.
+ $errors = $this->xpath('//div[contains(@class, "error")]//li');
+ foreach ($errors as $error) {
+ $expected_key = array_search($error[0], $expected);
+ // If the error message is not one of the expected messages, fail.
+ if ($expected_key === FALSE) {
+ $this->fail(format_string("Unexpected error message: @error", array('@error' => $error[0])));
+ }
+ // Remove the expected message from the list once it is found.
+ else {
+ unset($expected[$expected_key]);
+ }
+ }
+
+ // Fail if any expected messages were not found.
+ foreach ($expected as $not_found) {
+ $this->fail(format_string("Found error message: @error", array('@error' => $not_found)));
+ }
+
+ // Verify that input elements are still empty.
+ $this->assertFieldByName('textfield', '');
+ $this->assertNoFieldChecked('edit-checkboxes-foo');
+ $this->assertNoFieldChecked('edit-checkboxes-bar');
+ $this->assertOptionSelected('edit-select', '');
+ $this->assertNoFieldChecked('edit-radios-foo');
+ $this->assertNoFieldChecked('edit-radios-bar');
+ $this->assertNoFieldChecked('edit-radios-optional-foo');
+ $this->assertNoFieldChecked('edit-radios-optional-bar');
+
+ // Submit again with required fields set and verify that there are no
+ // error messages.
+ $edit = array(
+ 'textfield' => $this->randomString(),
+ 'checkboxes[foo]' => TRUE,
+ 'select' => 'foo',
+ 'radios' => 'bar',
+ );
+ $this->drupalPost(NULL, $edit, 'Submit');
+ $this->assertNoFieldByXpath('//div[contains(@class, "error")]', FALSE, 'No error message is displayed when all required fields are filled.');
+ $this->assertRaw("The form_test_validate_required_form form was submitted successfully.", 'Validation form submitted successfully.');
+ }
+
+ /**
* Test default value handling for checkboxes.
*
* @see _form_test_checkbox()
@@ -261,7 +340,7 @@ class FormsTestCase extends DrupalWebTestCase {
// All the elements should be marked as disabled, including the ones below
// the disabled container.
- $this->assertEqual(count($disabled_elements), 34, t('The correct elements have the disabled property in the HTML code.'));
+ $this->assertEqual(count($disabled_elements), 36, 'The correct elements have the disabled property in the HTML code.');
$this->drupalPost(NULL, $edit, t('Submit'));
$returned_values['hijacked'] = drupal_json_decode($this->content);
@@ -375,8 +454,6 @@ class FormsTestCase extends DrupalWebTestCase {
* Tests building and processing of core form elements.
*/
class FormElementTestCase extends DrupalWebTestCase {
- protected $profile = 'testing';
-
public static function getInfo() {
return array(
'name' => 'Element processing',
@@ -396,7 +473,7 @@ class FormElementTestCase extends DrupalWebTestCase {
$this->drupalGet('form-test/placeholder-text');
$expected = 'placeholder-text';
// Test to make sure non-textarea elements have the proper placeholder text.
- foreach (array('textfield', 'tel', 'password') as $type) {
+ foreach (array('textfield', 'tel', 'url', 'password', 'email') as $type) {
$element = $this->xpath('//input[@id=:id and @placeholder=:expected]', array(
':id' => 'edit-' . $type,
':expected' => $expected,
@@ -467,7 +544,7 @@ class FormAlterTestCase extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('form_test');
+ parent::setUp(array('block', 'form_test'));
}
/**
@@ -1139,7 +1216,7 @@ class FormStateValuesCleanAdvancedTestCase extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('form_test');
+ parent::setUp(array('file', 'form_test'));
}
/**
@@ -1183,6 +1260,8 @@ class FormsRebuildTestCase extends DrupalWebTestCase {
function setUp() {
parent::setUp('form_test');
+ $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
+
$this->web_user = $this->drupalCreateUser(array('access content'));
$this->drupalLogin($this->web_user);
}
@@ -1627,3 +1706,92 @@ class FormCheckboxTestCase extends DrupalWebTestCase {
}
}
}
+
+/**
+ * Tests email element.
+ */
+class FormEmailTestCase extends DrupalWebTestCase {
+ protected $profile = 'testing';
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Form API email',
+ 'description' => 'Tests the form API email element.',
+ 'group' => 'Form API',
+ );
+ }
+
+ function setUp() {
+ parent::setUp('form_test');
+ }
+
+ /**
+ * Tests that #type 'email' fields are properly validated.
+ */
+ function testFormEmail() {
+ $edit = array();
+ $edit['email'] = 'invalid';
+ $edit['email_required'] = ' ';
+ $this->drupalPost('form-test/email', $edit, 'Submit');
+ $this->assertRaw(t('The e-mail address %mail is not valid.', array('%mail' => 'invalid')));
+ $this->assertRaw(t('!name field is required.', array('!name' => 'Address')));
+
+ $edit = array();
+ $edit['email_required'] = ' foo.bar@example.com ';
+ $values = drupal_json_decode($this->drupalPost('form-test/email', $edit, 'Submit'));
+ $this->assertIdentical($values['email'], '');
+ $this->assertEqual($values['email_required'], 'foo.bar@example.com');
+
+ $edit = array();
+ $edit['email'] = 'foo@example.com';
+ $edit['email_required'] = 'example@drupal.org';
+ $values = drupal_json_decode($this->drupalPost('form-test/email', $edit, 'Submit'));
+ $this->assertEqual($values['email'], 'foo@example.com');
+ $this->assertEqual($values['email_required'], 'example@drupal.org');
+ }
+}
+
+/**
+ * Tests url element.
+ */
+class FormUrlTestCase extends DrupalWebTestCase {
+ protected $profile = 'testing';
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Form API url',
+ 'description' => 'Tests the form API url element.',
+ 'group' => 'Form API',
+ );
+ }
+
+ public function setUp() {
+ parent::setUp('form_test');
+ }
+
+ /**
+ * Tests that #type 'url' fields are properly validated and trimmed.
+ */
+ function testFormUrl() {
+ $edit = array();
+ $edit['url'] = 'http://';
+ $edit['url_required'] = ' ';
+ $this->drupalPost('form-test/url', $edit, 'Submit');
+ $this->assertRaw(t('The URL %url is not valid.', array('%url' => 'http://')));
+ $this->assertRaw(t('!name field is required.', array('!name' => 'Required URL')));
+
+ $edit = array();
+ $edit['url'] = "\n";
+ $edit['url_required'] = 'http://example.com/ ';
+ $values = drupal_json_decode($this->drupalPost('form-test/url', $edit, 'Submit'));
+ $this->assertIdentical($values['url'], '');
+ $this->assertEqual($values['url_required'], 'http://example.com/');
+
+ $edit = array();
+ $edit['url'] = 'http://foo.bar.example.com/';
+ $edit['url_required'] = 'http://drupal.org/node/1174630?page=0&foo=bar#new';
+ $values = drupal_json_decode($this->drupalPost('form-test/url', $edit, 'Submit'));
+ $this->assertEqual($values['url'], $edit['url']);
+ $this->assertEqual($values['url_required'], $edit['url_required']);
+ }
+}
diff --git a/core/modules/simpletest/tests/form_test.module b/core/modules/simpletest/tests/form_test.module
index 76e5c26..4b0f295 100644
--- a/core/modules/simpletest/tests/form_test.module
+++ b/core/modules/simpletest/tests/form_test.module
@@ -13,21 +13,28 @@ function form_test_menu() {
'title' => 'Form altering test',
'page callback' => 'drupal_get_form',
'page arguments' => array('form_test_alter_form'),
- 'access arguments' => array('access content'),
+ 'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
$items['form-test/validate'] = array(
'title' => 'Form validation handlers test',
'page callback' => 'drupal_get_form',
'page arguments' => array('form_test_validate_form'),
- 'access arguments' => array('access content'),
+ 'access callback' => TRUE,
+ 'type' => MENU_CALLBACK,
+ );
+ $items['form-test/validate-required'] = array(
+ 'title' => 'Form #required validation',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('form_test_validate_required_form'),
+ 'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
$items['form-test/limit-validation-errors'] = array(
'title' => 'Form validation with some error suppression',
'page callback' => 'drupal_get_form',
'page arguments' => array('form_test_limit_validation_errors_form'),
- 'access arguments' => array('access content'),
+ 'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
@@ -35,28 +42,28 @@ function form_test_menu() {
'title' => 'Tableselect checkboxes test',
'page callback' => 'drupal_get_form',
'page arguments' => array('_form_test_tableselect_multiple_true_form'),
- 'access arguments' => array('access content'),
+ 'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
$items['form_test/tableselect/multiple-false'] = array(
'title' => 'Tableselect radio button test',
'page callback' => 'drupal_get_form',
'page arguments' => array('_form_test_tableselect_multiple_false_form'),
- 'access arguments' => array('access content'),
+ 'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
$items['form_test/tableselect/empty-text'] = array(
'title' => 'Tableselect empty text test',
'page callback' => 'drupal_get_form',
'page arguments' => array('_form_test_tableselect_empty_form'),
- 'access arguments' => array('access content'),
+ 'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
$items['form_test/tableselect/advanced-select'] = array(
'title' => 'Tableselect js_select tests',
'page callback' => 'drupal_get_form',
'page arguments' => array('_form_test_tableselect_js_select_form'),
- 'access arguments' => array('access content'),
+ 'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
@@ -64,7 +71,7 @@ function form_test_menu() {
'title' => 'Vertical tabs tests',
'page callback' => 'drupal_get_form',
'page arguments' => array('_form_test_vertical_tabs_form'),
- 'access arguments' => array('access content'),
+ 'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
@@ -72,7 +79,7 @@ function form_test_menu() {
'title' => 'Form storage test',
'page callback' => 'drupal_get_form',
'page arguments' => array('form_test_storage_form'),
- 'access arguments' => array('access content'),
+ 'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
@@ -80,7 +87,7 @@ function form_test_menu() {
'title' => 'Form wrapper callback test',
'page callback' => 'form_test_wrapper_callback',
'page arguments' => array('form_test_wrapper_callback_form'),
- 'access arguments' => array('access content'),
+ 'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
@@ -88,7 +95,7 @@ function form_test_menu() {
'title' => 'Form state values clearance test',
'page callback' => 'drupal_get_form',
'page arguments' => array('form_test_form_state_values_clean_form'),
- 'access arguments' => array('access content'),
+ 'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
@@ -96,7 +103,7 @@ function form_test_menu() {
'title' => 'Form state values clearance advanced test',
'page callback' => 'drupal_get_form',
'page arguments' => array('form_test_form_state_values_clean_advanced_form'),
- 'access arguments' => array('access content'),
+ 'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
@@ -125,6 +132,18 @@ function form_test_menu() {
'page arguments' => array('form_test_checkboxes_radios'),
'access callback' => TRUE,
);
+ $items['form-test/email'] = array(
+ 'title' => 'E-Mail fields',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('form_test_email'),
+ 'access callback' => TRUE,
+ );
+ $items['form-test/url'] = array(
+ 'title' => t('URL'),
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('form_test_url'),
+ 'access callback' => TRUE,
+ );
$items['form-test/disabled-elements'] = array(
'title' => t('Form test'),
@@ -146,7 +165,7 @@ function form_test_menu() {
'title' => 'Form values preservation during rebuild test',
'page callback' => 'drupal_get_form',
'page arguments' => array('form_test_form_rebuild_preserve_values_form'),
- 'access arguments' => array('access content'),
+ 'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
@@ -154,7 +173,7 @@ function form_test_menu() {
'title' => 'Form label test',
'page callback' => 'drupal_get_form',
'page arguments' => array('form_label_test_form'),
- 'access arguments' => array('access content'),
+ 'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
@@ -346,6 +365,52 @@ function form_test_validate_form_validate(&$form, &$form_state) {
}
/**
+ * Form constructor to test the #required property.
+ */
+function form_test_validate_required_form($form, &$form_state) {
+ $options = drupal_map_assoc(array('foo', 'bar'));
+
+ $form['textfield'] = array(
+ '#type' => 'textfield',
+ '#title' => 'Textfield',
+ '#required' => TRUE,
+ );
+ $form['checkboxes'] = array(
+ '#type' => 'checkboxes',
+ '#title' => 'Checkboxes',
+ '#options' => $options,
+ '#required' => TRUE,
+ );
+ $form['select'] = array(
+ '#type' => 'select',
+ '#title' => 'Select',
+ '#options' => $options,
+ '#required' => TRUE,
+ );
+ $form['radios'] = array(
+ '#type' => 'radios',
+ '#title' => 'Radios',
+ '#options' => $options,
+ '#required' => TRUE,
+ );
+ $form['radios_optional'] = array(
+ '#type' => 'radios',
+ '#title' => 'Radios (optional)',
+ '#options' => $options,
+ );
+ $form['actions'] = array('#type' => 'actions');
+ $form['actions']['submit'] = array('#type' => 'submit', '#value' => 'Submit');
+ return $form;
+}
+
+/**
+ * Form submission handler for form_test_validate_required_form().
+ */
+function form_test_validate_required_form_submit($form, &$form_state) {
+ drupal_set_message('The form_test_validate_required_form form was submitted successfully.');
+}
+
+/**
* Builds a simple form with a button triggering partial validation.
*/
function form_test_limit_validation_errors_form($form, &$form_state) {
@@ -1027,7 +1092,7 @@ function form_test_select_submit($form, &$form_state) {
* Builds a form to test the placeholder attribute.
*/
function form_test_placeholder_test($form, &$form_state) {
- foreach (array('textfield', 'textarea', 'password', 'tel') as $type) {
+ foreach (array('textfield', 'textarea', 'url', 'password', 'tel', 'email') as $type) {
$form[$type] = array(
'#type' => $type,
'#title' => $type,
@@ -1098,6 +1163,72 @@ function form_test_checkboxes_radios($form, &$form_state, $customize = FALSE) {
}
/**
+ * Form constructor for testing #type 'email' elements.
+ *
+ * @see form_test_email_submit()
+ * @ingroup forms
+ */
+function form_test_email($form, &$form_state) {
+ $form['email'] = array(
+ '#type' => 'email',
+ '#title' => 'E-Mail address',
+ '#description' => 'An e-mail address.',
+ );
+ $form['email_required'] = array(
+ '#type' => 'email',
+ '#title' => 'Address',
+ '#required' => TRUE,
+ '#description' => 'A required e-mail address field.',
+ );
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#value' => 'Submit',
+ );
+ return $form;
+}
+
+/**
+ * Form submission handler for form_test_email().
+ */
+function form_test_email_submit($form, &$form_state) {
+ drupal_json_output($form_state['values']);
+ exit();
+}
+
+/**
+ * Form constructor for testing #type 'url' elements.
+ *
+ * @see form_test_url_submit()
+ * @ingroup forms
+ */
+function form_test_url($form, &$form_state) {
+ $form['url'] = array(
+ '#type' => 'url',
+ '#title' => 'Optional URL',
+ '#description' => 'An optional URL field.',
+ );
+ $form['url_required'] = array(
+ '#type' => 'url',
+ '#title' => 'Required URL',
+ '#description' => 'A required URL field.',
+ '#required' => TRUE,
+ );
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#value' => 'Submit',
+ );
+ return $form;
+}
+
+/**
+ * Form submission handler for form_test_url().
+ */
+function form_test_url_submit($form, &$form_state) {
+ drupal_json_output($form_state['values']);
+ exit();
+}
+
+/**
* Build a form to test disabled elements.
*/
function _form_test_disabled_elements($form, &$form_state) {
@@ -1196,7 +1327,7 @@ function _form_test_disabled_elements($form, &$form_state) {
$form['disabled_container'] = array(
'#disabled' => TRUE,
);
- foreach (array('textfield', 'textarea', 'hidden', 'tel') as $type) {
+ foreach (array('textfield', 'textarea', 'hidden', 'tel', 'url') as $type) {
$form['disabled_container']['disabled_container_' . $type] = array(
'#type' => $type,
'#title' => $type,
@@ -1205,6 +1336,22 @@ function _form_test_disabled_elements($form, &$form_state) {
);
}
+ // Try to hijack the email field with a valid email.
+ $form['disabled_container']['disabled_container_email'] = array(
+ '#type' => 'email',
+ '#title' => 'email',
+ '#default_value' => 'foo@example.com',
+ '#test_hijack_value' => 'bar@example.com',
+ );
+
+ // Try to hijack the URL field with a valid URL.
+ $form['disabled_container']['disabled_container_url'] = array(
+ '#type' => 'url',
+ '#title' => 'url',
+ '#default_value' => 'http://example.com',
+ '#test_hijack_value' => 'http://example.com/foo',
+ );
+
// Text format.
$form['text_format'] = array(
'#type' => 'text_format',
@@ -1617,7 +1764,7 @@ function form_test_two_instances() {
'uid' => $user->uid,
'name' => (isset($user->name) ? $user->name : ''),
'type' => 'page',
- 'langcode' => LANGUAGE_NONE,
+ 'langcode' => LANGUAGE_NOT_SPECIFIED,
);
$node2 = clone($node1);
$return['node_form_1'] = drupal_get_form('page_node_form', $node1);
diff --git a/core/modules/simpletest/tests/image.test b/core/modules/simpletest/tests/image.test
index ab008e5..deead57 100644
--- a/core/modules/simpletest/tests/image.test
+++ b/core/modules/simpletest/tests/image.test
@@ -465,8 +465,12 @@ class ImageToolkitGdTestCase extends DrupalWebTestCase {
/**
* Tests the file move function for managed files.
+ *
+ * @todo This test belongs to File module.
*/
class ImageFileMoveTest extends ImageToolkitTestCase {
+ protected $profile = 'standard';
+
public static function getInfo() {
return array(
'name' => 'Image moving',
diff --git a/core/modules/simpletest/tests/mail.test b/core/modules/simpletest/tests/mail.test
index 7425257..5d33102 100644
--- a/core/modules/simpletest/tests/mail.test
+++ b/core/modules/simpletest/tests/mail.test
@@ -4,7 +4,13 @@
* @file
* Test the Drupal mailing system.
*/
-class MailTestCase extends DrupalWebTestCase implements MailSystemInterface {
+
+use Drupal\Core\Mail\MailInterface;
+
+/**
+ * Defines a mail class used for testing.
+ */
+class MailTestCase extends DrupalWebTestCase implements MailInterface {
/**
* The most recent message that was sent through the test case.
*
@@ -17,7 +23,7 @@ class MailTestCase extends DrupalWebTestCase implements MailSystemInterface {
return array(
'name' => 'Mail system',
'description' => 'Performs tests on the pluggable mailing framework.',
- 'group' => 'System',
+ 'group' => 'Mail',
);
}
@@ -31,7 +37,7 @@ class MailTestCase extends DrupalWebTestCase implements MailSystemInterface {
/**
* Assert that the pluggable mail system is functional.
*/
- function testPluggableFramework() {
+ public function testPluggableFramework() {
global $language_interface;
// Use MailTestCase for sending a message.
@@ -46,7 +52,7 @@ class MailTestCase extends DrupalWebTestCase implements MailSystemInterface {
*
* @see simpletest_mail_alter()
*/
- function testCancelMessage() {
+ public function testCancelMessage() {
global $language;
// Reset the class variable holding a copy of the last sent message.
@@ -62,7 +68,7 @@ class MailTestCase extends DrupalWebTestCase implements MailSystemInterface {
/**
* Concatenate and wrap the e-mail body for plain-text mails.
*
- * @see DefaultMailSystem
+ * @see Drupal\Core\Mail\PhpMail
*/
public function format(array $message) {
// Join the body array into one string.
@@ -104,7 +110,7 @@ class DrupalHtmlToTextTestCase extends DrupalWebTestCase {
* An HTML representation of the text string that, when displayed in a
* browser, represents the PHP source code equivalent of $text.
*/
- function stringToHtml($text) {
+ protected function stringToHtml($text) {
return '"' .
str_replace(
array("\n", ' '),
@@ -126,7 +132,7 @@ class DrupalHtmlToTextTestCase extends DrupalWebTestCase {
* (optional) An array of allowed tags, or NULL to default to the full
* set of tags supported by drupal_html_to_text().
*/
- function assertHtmlToText($html, $text, $message, $allowed_tags = NULL) {
+ protected function assertHtmlToText($html, $text, $message, $allowed_tags = NULL) {
preg_match_all('/<([a-z0-6]+)/', drupal_strtolower($html), $matches);
$tested_tags = implode(', ', array_unique($matches[1]));
$message .= ' (' . $tested_tags . ')';
@@ -145,7 +151,7 @@ class DrupalHtmlToTextTestCase extends DrupalWebTestCase {
/**
* Test all supported tags of drupal_html_to_text().
*/
- function testTags() {
+ public function testTags() {
global $base_path, $base_url;
$tests = array(
// @todo Trailing linefeeds should be trimmed.
@@ -240,7 +246,7 @@ class DrupalHtmlToTextTestCase extends DrupalWebTestCase {
/**
* Test $allowed_tags argument of drupal_html_to_text().
*/
- function testDrupalHtmlToTextArgs() {
+ public function testDrupalHtmlToTextArgs() {
// The second parameter of drupal_html_to_text() overrules the allowed tags.
$this->assertHtmlToText(
'Drupal Drupal Drupal',
@@ -273,7 +279,7 @@ class DrupalHtmlToTextTestCase extends DrupalWebTestCase {
/**
* Test that whitespace is collapsed.
*/
- function testDrupalHtmltoTextCollapsesWhitespace() {
+ public function testDrupalHtmltoTextCollapsesWhitespace() {
$input = "Drupal Drupal\n\nDrupal
Drupal Drupal\n\nDrupal
Drupal Drupal\n\nDrupal";
// @todo The whitespace should be collapsed.
$collapsed = "Drupal Drupal\n\nDrupalDrupal Drupal\n\nDrupalDrupal Drupal\n\nDrupal\n\n";
@@ -289,7 +295,7 @@ class DrupalHtmlToTextTestCase extends DrupalWebTestCase {
* Test that text separated by block-level tags in HTML get separated by
* (at least) a newline in the plaintext version.
*/
- function testDrupalHtmlToTextBlockTagToNewline() {
+ public function testDrupalHtmlToTextBlockTagToNewline() {
$input = '[text]'
. '[blockquote]
'
. '
[br]'
@@ -339,7 +345,7 @@ class DrupalHtmlToTextTestCase extends DrupalWebTestCase {
/**
* Test that headers are properly separated from surrounding text.
*/
- function testHeaderSeparation() {
+ public function testHeaderSeparation() {
$html = 'DrupalDrupal
Drupal';
// @todo There should be more space above the header than below it.
$text = "Drupal\n======== DRUPAL ==============================================================\n\nDrupal\n";
@@ -364,7 +370,7 @@ class DrupalHtmlToTextTestCase extends DrupalWebTestCase {
/**
* Test that footnote references are properly generated.
*/
- function testFootnoteReferences() {
+ public function testFootnoteReferences() {
global $base_path, $base_url;
$source = 'Host and path'
. '
Host, no path'
@@ -389,7 +395,7 @@ class DrupalHtmlToTextTestCase extends DrupalWebTestCase {
* Test that combinations of paragraph breaks, line breaks, linefeeds,
* and spaces are properly handled.
*/
- function testDrupalHtmlToTextParagraphs() {
+ public function testDrupalHtmlToTextParagraphs() {
$tests = array();
$tests[] = array(
'html' => "line 1
\nline 2
line 3\n
line 4
paragraph
",
@@ -418,7 +424,7 @@ class DrupalHtmlToTextTestCase extends DrupalWebTestCase {
* RFC 821 says, "The maximum total length of a text line including the
* is 1000 characters."
*/
- function testVeryLongLineWrap() {
+ public function testVeryLongLineWrap() {
$input = 'Drupal
' . str_repeat('x', 2100) . '>
Drupal';
$output = drupal_html_to_text($input);
// This awkward construct comes from includes/mail.inc lines 8-13.
diff --git a/core/modules/simpletest/tests/menu.test b/core/modules/simpletest/tests/menu.test
index 5a173b1..41379ad 100644
--- a/core/modules/simpletest/tests/menu.test
+++ b/core/modules/simpletest/tests/menu.test
@@ -132,12 +132,30 @@ class MenuRouterTestCase extends DrupalWebTestCase {
function setUp() {
// Enable dummy module that implements hook_menu.
- parent::setUp('menu_test');
+ parent::setUp(array('block', 'menu_test'));
+
// Make the tests below more robust by explicitly setting the default theme
// and administrative theme that they expect.
theme_enable(array('bartik'));
variable_set('theme_default', 'bartik');
variable_set('admin_theme', 'seven');
+ theme_disable(array('stark'));
+
+ // Enable navigation menu block.
+ db_merge('block')
+ ->key(array(
+ 'module' => 'system',
+ 'delta' => 'navigation',
+ 'theme' => 'bartik',
+ ))
+ ->fields(array(
+ 'status' => 1,
+ 'weight' => 0,
+ 'region' => 'sidebar_first',
+ 'pages' => '',
+ 'cache' => -1,
+ ))
+ ->execute();
}
/**
@@ -239,15 +257,15 @@ class MenuRouterTestCase extends DrupalWebTestCase {
* 'user' and 'user/register' gets redirected to the user edit page.
*/
function testAuthUserUserLogin() {
- $loggedInUser = $this->drupalCreateUser(array());
- $this->drupalLogin($loggedInUser);
+ $this->loggedInUser = $this->drupalCreateUser(array());
+ $this->drupalLogin($this->loggedInUser);
- $this->DrupalGet('user/login');
+ $this->drupalGet('user/login');
// Check that we got to 'user'.
$this->assertTrue($this->url == url('user', array('absolute' => TRUE)), t("Logged-in user redirected to q=user on accessing q=user/login"));
// user/register should redirect to user/UID/edit.
- $this->DrupalGet('user/register');
+ $this->drupalGet('user/register');
$this->assertTrue($this->url == url('user/' . $this->loggedInUser->uid . '/edit', array('absolute' => TRUE)), t("Logged-in user redirected to q=user/UID/edit on accessing q=user/register"));
}
@@ -321,46 +339,46 @@ class MenuRouterTestCase extends DrupalWebTestCase {
* Tests for menu_link_maintain().
*/
function testMenuLinkMaintain() {
- $admin_user = $this->drupalCreateUser(array('administer site configuration'));
+ $admin_user = $this->drupalCreateUser(array('access content', 'administer site configuration'));
$this->drupalLogin($admin_user);
// Create three menu items.
menu_link_maintain('menu_test', 'insert', 'menu_test_maintain/1', 'Menu link #1');
- menu_link_maintain('menu_test', 'insert', 'menu_test_maintain/1', 'Menu link #1-1');
+ menu_link_maintain('menu_test', 'insert', 'menu_test_maintain/1', 'Menu link #1-main');
menu_link_maintain('menu_test', 'insert', 'menu_test_maintain/2', 'Menu link #2');
// Move second link to the main-menu, to test caching later on.
db_update('menu_links')
->fields(array('menu_name' => 'main-menu'))
- ->condition('link_title', 'Menu link #1-1')
+ ->condition('link_title', 'Menu link #1-main')
->condition('customized', 0)
->condition('module', 'menu_test')
->execute();
- menu_cache_clear('main-menu');
+ menu_cache_clear_all();
// Load front page.
- $this->drupalGet('node');
- $this->assertLink(t('Menu link #1'), 0, 'Found menu link #1');
- $this->assertLink(t('Menu link #1-1'), 0, 'Found menu link #1-1');
- $this->assertLink(t('Menu link #2'), 0, 'Found menu link #2');
+ $this->drupalGet('');
+ $this->assertLink('Menu link #1');
+ $this->assertLink('Menu link #1-main');
+ $this->assertLink('Menu link #2');
// Rename all links for the given path.
menu_link_maintain('menu_test', 'update', 'menu_test_maintain/1', 'Menu link updated');
// Load a different page to be sure that we have up to date information.
$this->drupalGet('menu_test_maintain/1');
- $this->assertLink(t('Menu link updated'), 0, t('Found updated menu link'));
- $this->assertNoLink(t('Menu link #1'), 0, t('Not found menu link #1'));
- $this->assertNoLink(t('Menu link #1'), 0, t('Not found menu link #1-1'));
- $this->assertLink(t('Menu link #2'), 0, t('Found menu link #2'));
+ $this->assertLink('Menu link updated');
+ $this->assertNoLink('Menu link #1');
+ $this->assertNoLink('Menu link #1-main');
+ $this->assertLink('Menu link #2');
// Delete all links for the given path.
menu_link_maintain('menu_test', 'delete', 'menu_test_maintain/1', '');
// Load a different page to be sure that we have up to date information.
$this->drupalGet('menu_test_maintain/2');
- $this->assertNoLink(t('Menu link updated'), 0, t('Not found deleted menu link'));
- $this->assertNoLink(t('Menu link #1'), 0, t('Not found menu link #1'));
- $this->assertNoLink(t('Menu link #1'), 0, t('Not found menu link #1-1'));
- $this->assertLink(t('Menu link #2'), 0, t('Found menu link #2'));
+ $this->assertNoLink('Menu link updated');
+ $this->assertNoLink('Menu link #1');
+ $this->assertNoLink('Menu link #1-main');
+ $this->assertLink('Menu link #2');
}
/**
@@ -647,9 +665,6 @@ class MenuRouterTestCase extends DrupalWebTestCase {
* Tests for menu links.
*/
class MenuLinksUnitTestCase extends DrupalWebTestCase {
- // Use the lightweight testing profile for this test.
- protected $profile = 'testing';
-
public static function getInfo() {
return array(
'name' => 'Menu links',
@@ -1017,6 +1032,8 @@ class MenuTreeOutputTestCase extends DrupalWebTestCase {
* Menu breadcrumbs related tests.
*/
class MenuBreadcrumbTestCase extends MenuWebTestCase {
+ protected $profile = 'standard';
+
public static function getInfo() {
return array(
'name' => 'Breadcrumbs',
@@ -1026,12 +1043,8 @@ class MenuBreadcrumbTestCase extends MenuWebTestCase {
}
function setUp() {
- $modules = func_get_args();
- if (isset($modules[0]) && is_array($modules[0])) {
- $modules = $modules[0];
- }
- $modules[] = 'menu_test';
- parent::setUp($modules);
+ parent::setUp(array('menu_test'));
+
$perms = array_keys(module_invoke_all('permission'));
$this->admin_user = $this->drupalCreateUser($perms);
$this->drupalLogin($this->admin_user);
@@ -1059,7 +1072,7 @@ class MenuBreadcrumbTestCase extends MenuWebTestCase {
$admin = $home + array('admin' => t('Administration'));
$config = $admin + array('admin/config' => t('Configuration'));
$type = 'article';
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
// Verify breadcrumbs for default local tasks.
$expected = array(
@@ -1520,12 +1533,7 @@ class MenuTrailTestCase extends MenuWebTestCase {
}
function setUp() {
- $modules = func_get_args();
- if (isset($modules[0]) && is_array($modules[0])) {
- $modules = $modules[0];
- }
- $modules[] = 'menu_test';
- parent::setUp($modules);
+ parent::setUp(array('block', 'menu_test'));
$this->admin_user = $this->drupalCreateUser(array('administer site configuration', 'access administration pages'));
$this->drupalLogin($this->admin_user);
diff --git a/core/modules/simpletest/tests/module.test b/core/modules/simpletest/tests/module.test
index c9601c9..81f4a6b 100644
--- a/core/modules/simpletest/tests/module.test
+++ b/core/modules/simpletest/tests/module.test
@@ -9,6 +9,9 @@
* Unit tests for the module API.
*/
class ModuleUnitTest extends DrupalWebTestCase {
+ // Requires Standard profile modules/dependencies.
+ protected $profile = 'standard';
+
public static function getInfo() {
return array(
'name' => 'Module API',
@@ -236,6 +239,38 @@ class ModuleUnitTest extends DrupalWebTestCase {
}
/**
+ * Tests class loading.
+ */
+class ModuleClassLoaderTestCase extends DrupalWebTestCase {
+ protected $profile = 'testing';
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Module class loader',
+ 'description' => 'Tests class loading for modules.',
+ 'group' => 'Module',
+ );
+ }
+
+ /**
+ * Tests that module-provided classes can be loaded when a module is enabled.
+ */
+ function testClassLoading() {
+ $expected = 'Drupal\\module_autoload_test\\SomeClass::testMethod() was invoked.';
+
+ module_enable(array('module_test', 'module_autoload_test'), FALSE);
+ $this->resetAll();
+ $this->drupalGet('module-test/class-loading');
+ $this->assertText($expected, t('Autoloader loads classes from an enabled module.'));
+
+ module_disable(array('module_autoload_test'), FALSE);
+ $this->resetAll();
+ $this->drupalGet('module-test/class-loading');
+ $this->assertNoText($expected, t('Autoloader does not load classes from a disabled module.'));
+ }
+}
+
+/**
* Unit tests for module installation.
*/
class ModuleInstallTestCase extends DrupalWebTestCase {
diff --git a/core/modules/simpletest/tests/module_autoload_test/lib/Drupal/module_autoload_test/SomeClass.php b/core/modules/simpletest/tests/module_autoload_test/lib/Drupal/module_autoload_test/SomeClass.php
new file mode 100644
index 0000000..33c2786
--- /dev/null
+++ b/core/modules/simpletest/tests/module_autoload_test/lib/Drupal/module_autoload_test/SomeClass.php
@@ -0,0 +1,14 @@
+ 'module_test_hook_dynamic_loading_invoke_all',
'access arguments' => array('access content'),
);
+ $items['module-test/class-loading'] = array(
+ 'title' => 'Test loading a class from another module',
+ 'page callback' => 'module_test_class_loading',
+ 'access callback' => TRUE,
+ );
return $items;
}
@@ -104,6 +109,21 @@ function module_test_hook_dynamic_loading_invoke_all() {
}
/**
+ * Page callback for 'class loading' test.
+ *
+ * This module does not have a dependency on module_autoload_test.module. If
+ * that module is enabled, this function should return the string
+ * 'Drupal\\module_autoload_test\\SomeClass::testMethod() was invoked.'. If
+ * that module is not enabled, this function should return nothing.
+ */
+function module_test_class_loading() {
+ if (class_exists('Drupal\module_autoload_test\SomeClass')) {
+ $obj = new Drupal\module_autoload_test\SomeClass();
+ return $obj->testMethod();
+ }
+}
+
+/**
* Implements hook_modules_enabled().
*/
function module_test_modules_enabled($modules) {
diff --git a/core/modules/simpletest/tests/password.test b/core/modules/simpletest/tests/password.test
index e0139e9..2797786 100644
--- a/core/modules/simpletest/tests/password.test
+++ b/core/modules/simpletest/tests/password.test
@@ -9,8 +9,6 @@
* Unit tests for password hashing API.
*/
class PasswordHashingTest extends DrupalWebTestCase {
- protected $profile = 'testing';
-
public static function getInfo() {
return array(
'name' => 'Password hashing',
diff --git a/core/modules/simpletest/tests/path.test b/core/modules/simpletest/tests/path.test
index 308ef64..fe6f734 100644
--- a/core/modules/simpletest/tests/path.test
+++ b/core/modules/simpletest/tests/path.test
@@ -330,7 +330,7 @@ class PathLookupTest extends DrupalWebTestCase {
'alias' => 'bar',
);
path_save($path);
- $this->assertEqual(drupal_lookup_path('source', $path['alias']), $path['source'], t('Newer alias record is returned when comparing two LANGUAGE_NONE paths with the same alias.'));
+ $this->assertEqual(drupal_lookup_path('source', $path['alias']), $path['source'], t('Newer alias record is returned when comparing two LANGUAGE_NOT_SPECIFIED paths with the same alias.'));
}
}
diff --git a/core/modules/simpletest/tests/queue.test b/core/modules/simpletest/tests/queue.test
new file mode 100644
index 0000000..e8f4c2c
--- /dev/null
+++ b/core/modules/simpletest/tests/queue.test
@@ -0,0 +1,120 @@
+ 'Queue functionality',
+ 'description' => 'Queues and dequeues a set of items to check the basic queue functionality.',
+ 'group' => 'Queue',
+ );
+ }
+
+ /**
+ * Tests the System queue.
+ */
+ public function testSystemQueue() {
+ // Create two queues.
+ $queue1 = new System($this->randomName());
+ $queue1->createQueue();
+ $queue2 = new System($this->randomName());
+ $queue2->createQueue();
+
+ $this->queueTest($queue1, $queue2);
+ }
+
+ /**
+ * Tests the Memory queue.
+ */
+ public function testMemoryQueue() {
+ // Create two queues.
+ $queue1 = new Memory($this->randomName());
+ $queue1->createQueue();
+ $queue2 = new Memory($this->randomName());
+ $queue2->createQueue();
+
+ $this->queueTest($queue1, $queue2);
+ }
+
+ /**
+ * Queues and dequeues a set of items to check the basic queue functionality.
+ *
+ * @param Drupal\Core\Queue\QueueInterface $queue1
+ * An instantiated queue object.
+ * @param Drupal\Core\Queue\QueueInterface $queue2
+ * An instantiated queue object.
+ */
+ protected function queueTest($queue1, $queue2) {
+ // Create four items.
+ $data = array();
+ for ($i = 0; $i < 4; $i++) {
+ $data[] = array($this->randomName() => $this->randomName());
+ }
+
+ // Queue items 1 and 2 in the queue1.
+ $queue1->createItem($data[0]);
+ $queue1->createItem($data[1]);
+
+ // Retrieve two items from queue1.
+ $items = array();
+ $new_items = array();
+
+ $items[] = $item = $queue1->claimItem();
+ $new_items[] = $item->data;
+
+ $items[] = $item = $queue1->claimItem();
+ $new_items[] = $item->data;
+
+ // First two dequeued items should match the first two items we queued.
+ $this->assertEqual($this->queueScore($data, $new_items), 2, t('Two items matched'));
+
+ // Add two more items.
+ $queue1->createItem($data[2]);
+ $queue1->createItem($data[3]);
+
+ $this->assertTrue($queue1->numberOfItems(), t('Queue 1 is not empty after adding items.'));
+ $this->assertFalse($queue2->numberOfItems(), t('Queue 2 is empty while Queue 1 has items'));
+
+ $items[] = $item = $queue1->claimItem();
+ $new_items[] = $item->data;
+
+ $items[] = $item = $queue1->claimItem();
+ $new_items[] = $item->data;
+
+ // All dequeued items should match the items we queued exactly once,
+ // therefore the score must be exactly 4.
+ $this->assertEqual($this->queueScore($data, $new_items), 4, t('Four items matched'));
+
+ // There should be no duplicate items.
+ $this->assertEqual($this->queueScore($new_items, $new_items), 4, t('Four items matched'));
+
+ // Delete all items from queue1.
+ foreach ($items as $item) {
+ $queue1->deleteItem($item);
+ }
+
+ // Check that both queues are empty.
+ $this->assertFalse($queue1->numberOfItems(), t('Queue 1 is empty'));
+ $this->assertFalse($queue2->numberOfItems(), t('Queue 2 is empty'));
+ }
+
+ /**
+ * Returns the number of equal items in two arrays.
+ */
+ protected function queueScore($items, $new_items) {
+ $score = 0;
+ foreach ($items as $item) {
+ foreach ($new_items as $new_item) {
+ if ($item === $new_item) {
+ $score++;
+ }
+ }
+ }
+ return $score;
+ }
+}
diff --git a/core/modules/simpletest/tests/session.test b/core/modules/simpletest/tests/session.test
index 746f632..6303ca5 100644
--- a/core/modules/simpletest/tests/session.test
+++ b/core/modules/simpletest/tests/session.test
@@ -139,7 +139,9 @@ class SessionTestCase extends DrupalWebTestCase {
$this->assertSessionEmpty(TRUE);
// The same behavior is expected when caching is enabled.
- variable_set('cache', 1);
+ $config = config('system.performance');
+ $config->set('cache', 1);
+ $config->save();
$this->drupalGet('');
$this->assertSessionCookie(FALSE);
$this->assertSessionEmpty(TRUE);
diff --git a/core/modules/simpletest/tests/theme.test b/core/modules/simpletest/tests/theme.test
index a3b5c3d..1550a80 100644
--- a/core/modules/simpletest/tests/theme.test
+++ b/core/modules/simpletest/tests/theme.test
@@ -9,8 +9,6 @@
* Unit tests for the Theme API.
*/
class ThemeUnitTest extends DrupalWebTestCase {
- protected $profile = 'testing';
-
public static function getInfo() {
return array(
'name' => 'Theme API',
@@ -100,7 +98,9 @@ class ThemeUnitTest extends DrupalWebTestCase {
// what is output to the HTML HEAD based on what is in a theme's .info file,
// so it doesn't matter what page we get, as long as it is themed with the
// test theme. First we test with CSS aggregation disabled.
- variable_set('preprocess_css', 0);
+ $config = config('system.performance');
+ $config->set('preprocess_css', 0);
+ $config->save();
$this->drupalGet('theme-test/suggestion');
$this->assertNoText('system.base.css', t('The theme\'s .info file is able to override a module CSS file from being added to the page.'));
@@ -108,9 +108,11 @@ class ThemeUnitTest extends DrupalWebTestCase {
// triggered during drupal_build_css_cache() when a source file doesn't
// exist. Then allow remaining tests to continue with aggregation disabled
// by default.
- variable_set('preprocess_css', 1);
+ $config->set('preprocess_css', 1);
+ $config->save();
$this->drupalGet('theme-test/suggestion');
- variable_set('preprocess_css', 0);
+ $config->set('preprocess_css', 0);
+ $config->save();
}
/**
@@ -218,8 +220,6 @@ class ThemeTableUnitTest extends DrupalWebTestCase {
* Tests for common theme functions.
*/
class ThemeFunctionsTestCase extends DrupalWebTestCase {
- protected $profile = 'testing';
-
public static function getInfo() {
return array(
'name' => 'Theme functions',
@@ -495,8 +495,11 @@ class ThemeHookInitUnitTest extends DrupalWebTestCase {
*/
function testThemeInitializationHookInit() {
$this->drupalGet('theme-test/hook-init');
- $this->assertRaw('Themed output generated in hook_init()', t('Themed output generated in hook_init() correctly appears on the page.'));
- $this->assertRaw('bartik/css/style.css', t("The default theme's CSS appears on the page when the theme system is initialized in hook_init()."));
+ // Verify that themed output generated in hook_init() appears.
+ $this->assertRaw('Themed output generated in hook_init()');
+ // Verify that the default theme's CSS still appears when the theme system
+ // is initialized in hook_init().
+ $this->assertRaw('stark/layout.css');
}
}
diff --git a/core/modules/simpletest/tests/upgrade/drupal-7.language.database.php b/core/modules/simpletest/tests/upgrade/drupal-7.language.database.php
index c231f84..99dc318 100644
--- a/core/modules/simpletest/tests/upgrade/drupal-7.language.database.php
+++ b/core/modules/simpletest/tests/upgrade/drupal-7.language.database.php
@@ -183,6 +183,19 @@ db_insert('languages')->fields(array(
'weight' => '0',
'javascript' => '',
))
+->values(array(
+ 'language' => 'hr',
+ 'name' => 'Croatian',
+ 'native' => 'Hrvatski',
+ 'direction' => '0',
+ 'enabled' => '1',
+ 'plurals' => '3',
+ 'formula' => '((($n%10)==1)&&(($n%100)!=11))?(0):((((($n%10)>=2)&&(($n%10)<=4))&&((($n%100)<10)||(($n%100)>=20)))?(1):2));',
+ 'domain' => '',
+ 'prefix' => '',
+ 'weight' => '0',
+ 'javascript' => '',
+))
->execute();
// Add locales_source table from locale.install schema and fill with some
@@ -413,6 +426,30 @@ db_insert('locales_source')->fields(array(
'context' => '',
'version' => 'none',
))
+->values(array(
+ 'lid' => '22',
+ 'location' => '',
+ 'textgroup' => 'default',
+ 'source' => '1 byte',
+ 'context' => '',
+ 'version' => 'none',
+))
+->values(array(
+ 'lid' => '23',
+ 'location' => '',
+ 'textgroup' => 'default',
+ 'source' => '@count bytes',
+ 'context' => '',
+ 'version' => 'none',
+))
+->values(array(
+ 'lid' => '24',
+ 'location' => '',
+ 'textgroup' => 'default',
+ 'source' => '@count[2] bytes',
+ 'context' => '',
+ 'version' => 'none',
+))
->execute();
// Add locales_target table from locale.install schema.
@@ -472,6 +509,49 @@ db_create_table('locales_target', array(
'module' => 'locale',
'name' => 'locales_target',
));
+db_insert('locales_target')->fields(array(
+ 'lid',
+ 'translation',
+ 'language',
+ 'plid',
+ 'plural',
+))
+->values(array(
+ 'lid' => 22,
+ 'translation' => '1 byte',
+ 'language' => 'ca',
+ 'plid' => 0,
+ 'plural' => 0,
+))
+->values(array(
+ 'lid' => 23,
+ 'translation' => '@count bytes',
+ 'language' => 'ca',
+ 'plid' => 22,
+ 'plural' => 1,
+))
+->values(array(
+ 'lid' => 22,
+ 'translation' => '@count bajt',
+ 'language' => 'hr',
+ 'plid' => 0,
+ 'plural' => 0,
+))
+->values(array(
+ 'lid' => 23,
+ 'translation' => '@count bajta',
+ 'language' => 'hr',
+ 'plid' => 22,
+ 'plural' => 1,
+))
+->values(array(
+ 'lid' => 24,
+ 'translation' => '@count[2] bajtova',
+ 'language' => 'hr',
+ 'plid' => 23,
+ 'plural' => 2,
+))
+->execute();
// Set up variables needed for language support.
db_insert('variable')->fields(array(
@@ -534,10 +614,10 @@ db_update('system')->fields(array(
// Add sample nodes to test language assignment and translation functionality.
// The first node is also used for testing comment language functionality. This
-// is a simple node with LANGUAGE_NONE as language code. The second node is a
-// Catalan node (language code 'ca'). The third and fourth node are a
-// translation set with an English source translation (language code 'en') and a
-// Chuvash translation (language code 'cv').
+// is a simple node with LANGUAGE_NOT_SPECIFIED as language code. The second
+// node is a Catalan node (language code 'ca'). The third and fourth node are a
+// translation set with an English source translation (language code 'en') and
+// a Chuvash translation (language code 'cv').
db_insert('node')->fields(array(
'nid',
'vid',
@@ -657,7 +737,7 @@ db_insert('node_revision')->fields(array(
'vid' => '50',
'uid' => '6',
'title' => 'Node title 38',
- 'log' => 'Added a LANGUAGE_NONE node to comment on.',
+ 'log' => 'Added a LANGUAGE_NOT_SPECIFIED node to comment on.',
'timestamp' => '1314997642',
'status' => '1',
'comment' => '2',
@@ -878,3 +958,26 @@ db_insert('field_revision_comment_body')->fields(array(
'comment_body_format' => 'filtered_html',
))
->execute();
+
+// Add a managed file.
+db_insert('file_managed')->fields(array(
+ 'fid',
+ 'uid',
+ 'filename',
+ 'uri',
+ 'filemime',
+ 'filesize',
+ 'status',
+ 'timestamp'
+))
+->values(array(
+ 'fid' => '1',
+ 'uid' => '1',
+ 'filename' => 'foo.txt',
+ 'uri' => 'public://foo.txt',
+ 'filemime' => 'text/plain',
+ 'filesize' => 0,
+ 'status' => 1,
+ 'timestamp' => '1314997642',
+))
+->execute();
diff --git a/core/modules/simpletest/tests/upgrade/upgrade.language.test b/core/modules/simpletest/tests/upgrade/upgrade.language.test
index b132e10..ecbbd12 100644
--- a/core/modules/simpletest/tests/upgrade/upgrade.language.test
+++ b/core/modules/simpletest/tests/upgrade/upgrade.language.test
@@ -32,6 +32,7 @@ class LanguageUpgradePathTestCase extends UpgradePathTestCase {
* Tests a successful upgrade.
*/
public function testLanguageUpgrade() {
+ db_update('users')->fields(array('language' => 'ca'))->condition('uid', '1')->execute();
$this->assertTrue($this->performUpgrade(), t('The upgrade was completed successfully.'));
// Ensure Catalan was properly upgraded to be the new default language.
@@ -62,7 +63,7 @@ class LanguageUpgradePathTestCase extends UpgradePathTestCase {
$translation_source_nid = 40;
$translation_nid = 41;
// Check directly for the $node->langcode property.
- $this->assertEqual(node_load($language_none_nid)->langcode, LANGUAGE_NONE, "'language' property was renamed to 'langcode' for LANGUAGE_NONE node.");
+ $this->assertEqual(node_load($language_none_nid)->langcode, LANGUAGE_NOT_SPECIFIED, "'language' property was renamed to 'langcode' for LANGUAGE_NOT_SPECIFIED node.");
$this->assertEqual(node_load($spanish_nid)->langcode, 'ca', "'language' property was renamed to 'langcode' for Catalan node.");
// Check that the translation table works correctly.
$this->drupalGet("node/$translation_source_nid/translate");
@@ -77,5 +78,62 @@ class LanguageUpgradePathTestCase extends UpgradePathTestCase {
$this->assertFieldByName('langcode');
$this->drupalGet('node/add/page');
$this->assertNoFieldByName('langcode');
+
+ // Check that the user language value was retained in both langcode and
+ // preferred_langcode.
+ $user = db_query('SELECT * FROM {users} WHERE uid = :uid', array(':uid' => 1))->fetchObject();
+ $this->assertEqual($user->langcode, 'ca');
+ $this->assertEqual($user->preferred_langcode, 'ca');
+
+ // A langcode property was added to vocabularies and terms. Check that
+ // existing vocabularies and terms got assigned the site default language.
+ $vocabulary = db_query('SELECT * FROM {taxonomy_vocabulary} WHERE vid = :vid', array(':vid' => 1))->fetchObject();
+ $this->assertEqual($vocabulary->langcode, 'ca');
+ $term = db_query('SELECT * FROM {taxonomy_term_data} WHERE tid = :tid', array(':tid' => 1))->fetchObject();
+ $this->assertEqual($term->langcode, 'ca');
+
+ // A langcode property was added to files. Check that existing files got
+ // assigned LANGUAGE_NOT_SPECIFIED.
+ $file = db_query('SELECT * FROM {file_managed} WHERE fid = :fid', array(':fid' => 1))->fetchObject();
+ $this->assertEqual($file->langcode, LANGUAGE_NOT_SPECIFIED);
+
+ // Check if language negotiation weights were renamed properly. This is a
+ // reproduction of the previous weights from the dump.
+ $expected_weights = array('locale-url' => '-8', 'locale-session' => '-6', 'locale-user' => '-4', 'locale-browser' => '-2', 'language-default' => '10');
+ // Check that locale_language_providers_weight_language is correctly
+ // renamed.
+ $current_weights = variable_get('locale_language_negotiation_methods_weight_language_interface', array());
+ $this->assertTrue(serialize($expected_weights) == serialize($current_weights), t('Language negotiation method weights upgraded.'));
+
+ // Look up migrated plural string.
+ $source_string = db_query('SELECT * FROM {locales_source} WHERE lid = 22')->fetchObject();
+ $this->assertEqual($source_string->source, implode(LOCALE_PLURAL_DELIMITER, array('1 byte', '@count bytes')));
+
+ $translation_string = db_query("SELECT * FROM {locales_target} WHERE lid = 22 AND language = 'hr'")->fetchObject();
+ $this->assertEqual($translation_string->translation, implode(LOCALE_PLURAL_DELIMITER, array('@count bajt', '@count bajta', '@count bajtova')));
+ $this->assertTrue(!isset($translation_string->plural), 'Chained plural indicator removed.');
+ $this->assertTrue(!isset($translation_string->plid), 'Chained plural indicator removed.');
+
+ $source_string = db_query('SELECT * FROM {locales_source} WHERE lid IN (23, 24)')->fetchObject();
+ $this->assertTrue(empty($source_string), 'Individual plural variant source removed');
+ $translation_string = db_query("SELECT * FROM {locales_target} WHERE lid IN (23, 24)")->fetchObject();
+ $this->assertTrue(empty($translation_string), 'Individual plural variant translation removed');
+
+ $translation_string = db_query("SELECT * FROM {locales_target} WHERE lid = 22 AND language = 'ca'")->fetchObject();
+ $this->assertEqual($translation_string->translation, implode(LOCALE_PLURAL_DELIMITER, array('1 byte', '@count bytes')));
+ }
+
+ /**
+ * Tests language domain upgrade path.
+ */
+ public function testLanguageUrlUpgrade() {
+ $language_domain = 'ca.example.com';
+ db_update('languages')->fields(array('domain' => 'http://' . $language_domain . ':8888'))->condition('language', 'ca')->execute();
+ variable_set('locale_language_negotiation_url_part', 1);
+
+ $this->assertTrue($this->performUpgrade(), t('The upgrade was completed successfully.'));
+
+ $domains = locale_language_negotiation_url_domains();
+ $this->assertTrue($domains['ca'] == $language_domain, t('Language domain for Catalan properly upgraded.'));
}
}
diff --git a/core/modules/simpletest/tests/uuid.test b/core/modules/simpletest/tests/uuid.test
new file mode 100644
index 0000000..0e1d679
--- /dev/null
+++ b/core/modules/simpletest/tests/uuid.test
@@ -0,0 +1,69 @@
+ 'UUID handling',
+ 'description' => "Test the handling of Universally Unique IDentifiers (UUIDs).",
+ 'group' => 'UUID',
+ );
+ }
+
+ public function setUp() {
+ // Initiate the generator. This will lazy-load uuid.inc.
+ $this->uuid = new Uuid();
+ parent::setUp();
+ }
+
+ /**
+ * Test generating a UUID.
+ */
+ public function testGenerateUuid() {
+ $uuid = $this->uuid->generate();
+ $this->assertTrue($this->uuid->isValid($uuid), 'UUID generation works.');
+ }
+
+ /**
+ * Test that generated UUIDs are unique.
+ */
+ public function testUuidIsUnique() {
+ $uuid1 = $this->uuid->generate();
+ $uuid2 = $this->uuid->generate();
+ $this->assertNotEqual($uuid1, $uuid2, 'Same UUID was not generated twice.');
+ }
+
+ /**
+ * Test UUID validation.
+ */
+ function testUuidValidation() {
+ // These valid UUIDs.
+ $uuid_fqdn = '6ba7b810-9dad-11d1-80b4-00c04fd430c8';
+ $uuid_min = '00000000-0000-0000-0000-000000000000';
+ $uuid_max = 'ffffffff-ffff-ffff-ffff-ffffffffffff';
+
+ $this->assertTrue($this->uuid->isValid($uuid_fqdn), t('FQDN namespace UUID (@uuid) is valid', array('@uuid' => $uuid_fqdn)));
+ $this->assertTrue($this->uuid->isValid($uuid_min), t('Minimum UUID value (@uuid) is valid', array('@uuid' => $uuid_min)));
+ $this->assertTrue($this->uuid->isValid($uuid_max), t('Maximum UUID value (@uuid) is valid', array('@uuid' => $uuid_max)));
+
+ // These are invalid UUIDs.
+ $invalid_format = '0ab26e6b-f074-4e44-9da-601205fa0e976';
+ $invalid_length = '0ab26e6b-f074-4e44-9daf-1205fa0e9761f';
+
+ $this->assertFalse($this->uuid->isValid($invalid_format), t('@uuid is not a valid UUID', array('@uuid' => $invalid_format)));
+ $this->assertFalse($this->uuid->isValid($invalid_length), t('@uuid is not a valid UUID', array('@uuid' => $invalid_length)));
+
+ }
+}
diff --git a/core/modules/statistics/statistics.test b/core/modules/statistics/statistics.test
index e3ae35c..62cec24 100644
--- a/core/modules/statistics/statistics.test
+++ b/core/modules/statistics/statistics.test
@@ -11,7 +11,12 @@
class StatisticsTestCase extends DrupalWebTestCase {
function setUp() {
- parent::setUp('statistics');
+ parent::setUp(array('node', 'block', 'statistics'));
+
+ // Create Basic page node type.
+ if ($this->profile != 'standard') {
+ $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
+ }
// Create user.
$this->blocking_user = $this->drupalCreateUser(array(
@@ -61,7 +66,12 @@ class StatisticsLoggingTestCase extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('statistics');
+ parent::setUp(array('statistics', 'block'));
+
+ // Create Basic page node type.
+ if ($this->profile != 'standard') {
+ $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
+ }
$this->auth_user = $this->drupalCreateUser(array('access content', 'create page content', 'edit own page content'));
@@ -69,7 +79,9 @@ class StatisticsLoggingTestCase extends DrupalWebTestCase {
$this->node = $this->drupalCreateNode(array('title' => $this->randomName(255), 'uid' => $this->auth_user->uid));
// Enable page caching.
- variable_set('cache', TRUE);
+ $config = config('system.performance');
+ $config->set('cache', 1);
+ $config->save();
// Enable access logging.
variable_set('statistics_enable_access_log', 1);
@@ -297,7 +309,12 @@ class StatisticsAdminTestCase extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('statistics');
+ parent::setUp(array('node', 'statistics'));
+
+ // Create Basic page node type.
+ if ($this->profile != 'standard') {
+ $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
+ }
$this->privileged_user = $this->drupalCreateUser(array('access statistics', 'administer statistics', 'view post access counter', 'create page content'));
$this->drupalLogin($this->privileged_user);
$this->test_node = $this->drupalCreateNode(array('type' => 'page', 'uid' => $this->privileged_user->uid));
@@ -380,7 +397,11 @@ class StatisticsAdminTestCase extends DrupalWebTestCase {
$timestamp = time();
$this->drupalPost(NULL, NULL, t('Cancel account'));
// Confirm account cancellation request.
- $this->drupalGet("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login));
+ $mails = $this->drupalGetMails();
+ $mail = end($mails);
+ preg_match('@http.+?(user/\d+/cancel/confirm/\d+/[^\s]+)@', $mail['body'], $matches);
+ $path = $matches[1];
+ $this->drupalGet($path);
$this->assertFalse(user_load($account->uid, TRUE), t('User is not found in the database.'));
$this->drupalGet('admin/reports/visitors');
diff --git a/core/modules/system/config/system.performance.xml b/core/modules/system/config/system.performance.xml
new file mode 100644
index 0000000..8edf1eb
--- /dev/null
+++ b/core/modules/system/config/system.performance.xml
@@ -0,0 +1,9 @@
+
+
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+
diff --git a/core/modules/locale/locale.api.php b/core/modules/system/language.api.php
similarity index 58%
rename from core/modules/locale/locale.api.php
rename to core/modules/system/language.api.php
index 6cf253e..aa8fd2f 100644
--- a/core/modules/locale/locale.api.php
+++ b/core/modules/system/language.api.php
@@ -2,7 +2,7 @@
/**
* @file
- * Hooks provided by the Locale module.
+ * Hooks provided by the base system for language support.
*/
/**
@@ -74,9 +74,9 @@ function hook_language_switch_links_alter(array &$links, $type, $path) {
* following key-value pairs:
* - "name": The human-readable language type identifier.
* - "description": A description of the language type.
- * - "fixed": A fixed array of language provider identifiers to use to
- * initialize this language. Defining this key makes the language type
- * non-configurable and will always use the specified providers in the given
+ * - "fixed": A fixed array of language negotiation method identifiers to use
+ * to initialize this language. Defining this key makes the language type
+ * non-configurable and will always use the specified methods in the given
* priority order.
*/
function hook_language_types_info() {
@@ -86,7 +86,7 @@ function hook_language_types_info() {
'description' => t('A custom language type.'),
),
'fixed_custom_language_type' => array(
- 'fixed' => array('custom_language_provider'),
+ 'fixed' => array('custom_language_negotiation_method'),
),
);
}
@@ -106,59 +106,59 @@ function hook_language_types_info_alter(array &$language_types) {
}
/**
- * Allow modules to define their own language providers.
+ * Allow modules to define their own language negotiation methods.
*
* @return
- * An array of language provider definitions. Each language provider has an
- * identifier key. The language provider definition is an associative array
- * that may contain the following key-value pairs:
- * - "types": An array of allowed language types. If a language provider does
- * not specify which language types it should be used with, it will be
- * available for all the configurable language types.
+ * An array of language negotiation method definitions. Each method has an
+ * identifier key. The language negotiation method definition is an indexed
+ * array that may contain the following key-value pairs:
+ * - "types": An array of allowed language types. If a language negotiation
+ * method does not specify which language types it should be used with, it
+ * will be available for all the configurable language types.
* - "callbacks": An array of functions that will be called to perform various
* tasks. Possible key-value pairs are:
- * - "language": Required. The callback that will determine the language
+ * - "negotiation": Required. The callback that will determine the language
* value.
- * - "switcher": The callback that will determine the language switch links
- * associated to the current language provider.
+ * - "language_switch": The callback that will determine the language
+ * switch links associated to the current language method.
* - "url_rewrite": The callback that will provide URL rewriting.
* - "file": A file that will be included before the callback is invoked; this
* allows callback functions to be in separate files.
- * - "weight": The default weight the language provider has.
+ * - "weight": The default weight the language negotiation method has.
* - "name": A human-readable identifier.
- * - "description": A description of the language provider.
- * - "config": An internal path pointing to the language provider
+ * - "description": A description of the language negotiation method.
+ * - "config": An internal path pointing to the language negotiation method
* configuration page.
* - "cache": The value Drupal's page cache should be set to for the current
- * language provider to be invoked.
+ * language negotiation method to be invoked.
*/
function hook_language_negotiation_info() {
return array(
- 'custom_language_provider' => array(
+ 'custom_language_negotiation_method' => array(
'callbacks' => array(
- 'language' => 'custom_language_provider_callback',
- 'switcher' => 'custom_language_switcher_callback',
- 'url_rewrite' => 'custom_language_url_rewrite_callback',
+ 'negotiation' => 'custom_negotiation_callback',
+ 'language_switch' => 'custom_language_switch_callback',
+ 'url_rewrite' => 'custom_url_rewrite_callback',
),
'file' => drupal_get_path('module', 'custom') . '/custom.module',
'weight' => -4,
'types' => array('custom_language_type'),
- 'name' => t('Custom language provider'),
- 'description' => t('This is a custom language provider.'),
+ 'name' => t('Custom language negotiation method'),
+ 'description' => t('This is a custom language negotiation method.'),
'cache' => 0,
),
);
}
/**
- * Perform alterations on language providers.
+ * Perform alterations on language negotiation methods.
*
- * @param $language_providers
- * Array of language provider definitions.
+ * @param $negotiation_info
+ * Array of language negotiation method definitions.
*/
-function hook_language_negotiation_info_alter(array &$language_providers) {
- if (isset($language_providers['custom_language_provider'])) {
- $language_providers['custom_language_provider']['config'] = 'admin/config/regional/language/detection/custom-language-provider';
+function hook_language_negotiation_info_alter(array &$negotiation_info) {
+ if (isset($negotiation_info['custom_language_method'])) {
+ $negotiation_info['custom_language_method']['config'] = 'admin/config/regional/language/detection/custom-language-method';
}
}
@@ -173,53 +173,6 @@ function hook_language_fallback_candidates_alter(array &$fallback_candidates) {
$fallback_candidates = array_reverse($fallback_candidates);
}
- /**
- * React to a language about to be added or updated in the system.
- *
- * @param $language
- * A language object.
- */
-function hook_locale_language_presave($language) {
- if ($language->default) {
- // React to a new default language.
- example_new_default_language($language);
- }
-}
-
-/**
- * React to a language that was just added to the system.
- *
- * @param $language
- * A language object.
- */
-function hook_locale_language_insert($language) {
- example_refresh_permissions();
-}
-
-/**
- * React to a language that was just updated in the system.
- *
- * @param $language
- * A language object.
- */
-function hook_locale_language_update($language) {
- example_refresh_permissions();
-}
-
-/**
- * Allow modules to react before the deletion of a language.
- *
- * @param $language
- * The language object of the language that is about to be deleted.
- */
-function hook_locale_language_delete($language) {
- // On nodes with this language, unset the language
- db_update('node')
- ->fields(array('language' => ''))
- ->condition('language', $language->langcode)
- ->execute();
-}
-
/**
* @} End of "addtogroup hooks".
*/
diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc
index d28ecfb..4d75dca 100644
--- a/core/modules/system/system.admin.inc
+++ b/core/modules/system/system.admin.inc
@@ -1373,6 +1373,7 @@ function system_ip_blocking($default_ip = '') {
'#theme' => 'table',
'#header' => $header,
'#rows' => $rows,
+ '#empty' => t('No blocked IP addresses available.'),
);
return $build;
@@ -1477,7 +1478,7 @@ function system_site_information_settings() {
'#description' => t("How this is used depends on your site's theme."),
);
$form['site_information']['site_mail'] = array(
- '#type' => 'textfield',
+ '#type' => 'email',
'#title' => t('E-mail address'),
'#default_value' => variable_get('site_mail', ini_get('sendmail_from')),
'#description' => t("The From address in automated e-mails sent during registration and new password requests, and other notifications. (Use an address ending in your site's domain to help prevent this e-mail being flagged as spam.)"),
@@ -1532,10 +1533,6 @@ function system_site_information_settings() {
* Validates the submitted site-information form.
*/
function system_site_information_settings_validate($form, &$form_state) {
- // Validate the e-mail address.
- if ($error = user_validate_mail($form_state['values']['site_mail'])) {
- form_set_error('site_mail', $error);
- }
// Check for empty front page path.
if (empty($form_state['values']['site_frontpage'])) {
// Set to default "user".
@@ -1641,10 +1638,11 @@ function system_logging_settings() {
* Form builder; Configure site performance settings.
*
* @ingroup forms
- * @see system_settings_form()
+ * @see system_performance_settings_submit().
*/
-function system_performance_settings() {
+function system_performance_settings($form, &$form_state) {
drupal_add_js(drupal_get_path('module', 'system') . '/system.js');
+ $config = config('system.performance');
$form['clear_cache'] = array(
'#type' => 'fieldset',
@@ -1662,11 +1660,10 @@ function system_performance_settings() {
'#title' => t('Caching'),
);
- $cache = variable_get('cache', 0);
$form['caching']['cache'] = array(
'#type' => 'checkbox',
'#title' => t('Cache pages for anonymous users'),
- '#default_value' => $cache,
+ '#default_value' => $config->get('cache'),
'#weight' => -2,
);
$period = drupal_map_assoc(array(0, 60, 180, 300, 600, 900, 1800, 2700, 3600, 10800, 21600, 32400, 43200, 86400), 'format_interval');
@@ -1674,16 +1671,16 @@ function system_performance_settings() {
$form['caching']['cache_lifetime'] = array(
'#type' => 'select',
'#title' => t('Minimum cache lifetime'),
- '#default_value' => variable_get('cache_lifetime', 0),
+ '#default_value' => $config->get('cache_lifetime'),
'#options' => $period,
- '#description' => t('Cached pages will not be re-created until at least this much time has elapsed.')
+ '#description' => t('Cached pages will not be re-created until at least this much time has elapsed.'),
);
$form['caching']['page_cache_maximum_age'] = array(
'#type' => 'select',
'#title' => t('Expiration of cached pages'),
- '#default_value' => variable_get('page_cache_maximum_age', 0),
+ '#default_value' => $config->get('page_cache_maximum_age'),
'#options' => $period,
- '#description' => t('The maximum time an external cache can use an old version of a page.')
+ '#description' => t('The maximum time an external cache can use an old version of a page.'),
);
$directory = 'public://';
@@ -1700,34 +1697,57 @@ function system_performance_settings() {
'#description' => t('External resources can be optimized automatically, which can reduce both the size and number of requests made to your website.') . $disabled_message,
);
- $js_hide = $cache ? '' : ' class="js-hide"';
+ $js_hide = $config->get('cache') ? '' : ' class="js-hide"';
$form['bandwidth_optimization']['page_compression'] = array(
'#type' => 'checkbox',
'#title' => t('Compress cached pages.'),
- '#default_value' => variable_get('page_compression', TRUE),
+ '#default_value' => $config->get('page_compression'),
'#prefix' => '
',
'#suffix' => '
',
);
$form['bandwidth_optimization']['preprocess_css'] = array(
'#type' => 'checkbox',
'#title' => t('Aggregate and compress CSS files.'),
- '#default_value' => intval(variable_get('preprocess_css', 0) && $is_writable),
+ '#default_value' => $config->get('preprocess_css'),
'#disabled' => $disabled,
);
$form['bandwidth_optimization']['preprocess_js'] = array(
'#type' => 'checkbox',
'#title' => t('Aggregate JavaScript files.'),
- '#default_value' => intval(variable_get('preprocess_js', 0) && $is_writable),
+ '#default_value' => $config->get('preprocess_js'),
'#disabled' => $disabled,
);
+ $form['actions'] = array('#type' => 'actions');
+ $form['actions']['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Save configuration'),
+ );
+
$form['#submit'][] = 'drupal_clear_css_cache';
$form['#submit'][] = 'drupal_clear_js_cache';
// This form allows page compression settings to be changed, which can
// invalidate the page cache, so it needs to be cleared on form submit.
$form['#submit'][] = 'system_clear_page_cache_submit';
+ $form['#submit'][] = 'system_performance_settings_submit';
- return system_settings_form($form);
+ return $form;
+}
+
+/**
+ * Form submission handler for system_performance_settings().
+ *
+ * @ingroup forms
+ */
+function system_performance_settings_submit($form, &$form_state) {
+ $config = config('system.performance');
+ $config->set('cache', $form_state['values']['cache']);
+ $config->set('cache_lifetime', $form_state['values']['cache_lifetime']);
+ $config->set('page_cache_maximum_age', $form_state['values']['page_cache_maximum_age']);
+ $config->set('page_compression', $form_state['values']['page_compression']);
+ $config->set('preprocess_css', $form_state['values']['preprocess_css']);
+ $config->set('preprocess_js', $form_state['values']['preprocess_js']);
+ $config->save();
}
/**
diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php
index 907b7b5..785b098 100644
--- a/core/modules/system/system.api.php
+++ b/core/modules/system/system.api.php
@@ -138,7 +138,7 @@ function hook_cron() {
':time' => REQUEST_TIME,
':never' => AGGREGATOR_CLEAR_NEVER,
));
- $queue = DrupalQueue::get('aggregator_feeds');
+ $queue = queue('aggregator_feeds');
foreach ($result as $feed) {
$queue->createItem($feed);
}
@@ -158,8 +158,8 @@ function hook_cron() {
* An associative array where the key is the queue name and the value is
* again an associative array. Possible keys are:
* - 'worker callback': The name of the function to call. It will be called
- * with one argument, the item created via DrupalQueue::createItem() in
- * hook_cron().
+ * with one argument, the item created via
+ * Drupal\Core\Queue\QueueInterface::createItem() in hook_cron().
* - 'time': (optional) How much time Drupal should spend on calling this
* worker in seconds. Defaults to 15.
*
@@ -2207,11 +2207,11 @@ function hook_modules_uninstalled($modules) {
* then keyed by the following values:
* - 'name' A short string to name the wrapper.
* - 'class' A string specifying the PHP class that implements the
- * DrupalStreamWrapperInterface interface.
+ * Drupal\Core\StreamWrapper\StreamWrapperInterface interface.
* - 'description' A string with a short description of what the wrapper does.
* - 'type' (Optional) A bitmask of flags indicating what type of streams this
* wrapper will access - local or remote, readable and/or writeable, etc.
- * Many shortcut constants are defined in stream_wrappers.inc. Defaults to
+ * Many shortcut constants are defined in file.inc. Defaults to
* STREAM_WRAPPERS_NORMAL which includes all of these bit flags:
* - STREAM_WRAPPERS_READ
* - STREAM_WRAPPERS_WRITE
@@ -2225,31 +2225,33 @@ function hook_stream_wrappers() {
return array(
'public' => array(
'name' => t('Public files'),
- 'class' => 'DrupalPublicStreamWrapper',
+ 'class' => 'Drupal\Core\StreamWrapper\PublicStream',
'description' => t('Public local files served by the webserver.'),
'type' => STREAM_WRAPPERS_LOCAL_NORMAL,
),
'private' => array(
'name' => t('Private files'),
- 'class' => 'DrupalPrivateStreamWrapper',
+ 'class' => 'Drupal\Core\StreamWrapper\PrivateStream',
'description' => t('Private local files served by Drupal.'),
'type' => STREAM_WRAPPERS_LOCAL_NORMAL,
),
'temp' => array(
'name' => t('Temporary files'),
- 'class' => 'DrupalTempStreamWrapper',
+ 'class' => 'Drupal\Core\StreamWrapper\TemporaryStream',
'description' => t('Temporary local files for upload and previews.'),
'type' => STREAM_WRAPPERS_LOCAL_HIDDEN,
),
'cdn' => array(
'name' => t('Content delivery network files'),
- 'class' => 'MyModuleCDNStreamWrapper',
+ // @todo: Fix the name of this class when we decide on module PSR-0 usage.
+ 'class' => 'MyModuleCDNStream',
'description' => t('Files served by a content delivery network.'),
// 'type' can be omitted to use the default of STREAM_WRAPPERS_NORMAL
),
'youtube' => array(
'name' => t('YouTube video'),
- 'class' => 'MyModuleYouTubeStreamWrapper',
+ // @todo: Fix the name of this class when we decide on module PSR-0 usage.
+ 'class' => 'MyModuleYouTubeStream',
'description' => t('Video streamed from YouTube.'),
// A module implementing YouTube integration may decide to support using
// the YouTube API for uploading video, but here, we assume that this
@@ -4040,9 +4042,9 @@ function hook_batch_alter(&$batch) {
/**
* Provide information on Updaters (classes that can update Drupal).
*
- * An Updater is a class that knows how to update various parts of the Drupal
- * file system, for example to update modules that have newer releases, or to
- * install a new theme.
+ * Drupal\Core\Updater\Updater is a class that knows how to update various parts
+ * of the Drupal file system, for example to update modules that have newer
+ * releases, or to install a new theme.
*
* @return
* An associative array of information about the updater(s) being provided.
@@ -4064,12 +4066,12 @@ function hook_batch_alter(&$batch) {
function hook_updater_info() {
return array(
'module' => array(
- 'class' => 'ModuleUpdater',
+ 'class' => 'Drupal\Core\Updater\Module',
'name' => t('Update modules'),
'weight' => 0,
),
'theme' => array(
- 'class' => 'ThemeUpdater',
+ 'class' => 'Drupal\Core\Updater\Theme',
'name' => t('Update themes'),
'weight' => 0,
),
diff --git a/core/modules/system/system.base.css b/core/modules/system/system.base.css
index 1723b33..68a1683 100644
--- a/core/modules/system/system.base.css
+++ b/core/modules/system/system.base.css
@@ -61,8 +61,6 @@ fieldset.collapsible .fieldset-legend {
/**
* Resizable textareas.
- *
- * @see textarea.js
*/
.form-textarea-wrapper textarea {
display: block;
@@ -72,13 +70,21 @@ fieldset.collapsible .fieldset-legend {
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
-.resizable-textarea .grippie {
- background: #eee url(../../misc/grippie.png) no-repeat center 2px;
- border: 1px solid #ddd;
- border-top-width: 0;
- cursor: s-resize;
- height: 9px;
- overflow: hidden;
+.resize-none {
+ resize: none;
+}
+.resize-vertical {
+ resize: vertical;
+ min-height: 2em;
+}
+.resize-horizontal {
+ resize: horizontal;
+ max-width: 100%;
+}
+.resize-both {
+ resize: both;
+ max-width: 100%;
+ min-height: 2em;
}
/**
diff --git a/core/modules/system/system.info b/core/modules/system/system.info
index c394849..afe4a81 100644
--- a/core/modules/system/system.info
+++ b/core/modules/system/system.info
@@ -4,10 +4,7 @@ package = Core
version = VERSION
core = 8.x
files[] = system.archiver.inc
-files[] = system.mail.inc
-files[] = system.queue.inc
files[] = system.tar.inc
-files[] = system.updater.inc
files[] = system.test
required = TRUE
configure = admin/config/system
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index d562bf6..2cbb615 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -697,6 +697,28 @@ function system_schema() {
$schema['cache_path'] = $schema['cache'];
$schema['cache_path']['description'] = 'Cache table for path alias lookup.';
+ $schema['config'] = array(
+ 'description' => 'Default active store for the configuration system.',
+ 'fields' => array(
+ 'name' => array(
+ 'description' => 'The identifier for the configuration entry, such as module.example (the name of the file, minus the file extension).',
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ 'default' => '',
+ ),
+ 'data' => array(
+ 'description' => 'The raw data for this configuration entry.',
+ 'type' => 'blob',
+ 'not null' => TRUE,
+ 'size' => 'big',
+ 'translatable' => TRUE,
+ ),
+ ),
+ 'primary key' => array('name'),
+ );
+
+
$schema['date_format_type'] = array(
'description' => 'Stores configured date format types.',
'fields' => array(
@@ -816,6 +838,13 @@ function system_schema() {
'not null' => TRUE,
'default' => '',
),
+ 'langcode' => array(
+ 'description' => 'The {language}.langcode of this file.',
+ 'type' => 'varchar',
+ 'length' => 12,
+ 'not null' => TRUE,
+ 'default' => '',
+ ),
'filemime' => array(
'description' => "The file's MIME type.",
'type' => 'varchar',
@@ -1478,7 +1507,7 @@ function system_schema() {
'default' => 0,
),
'cache' => array(
- 'description' => "The time of this user's last post. This is used when the site has specified a minimum_cache_lifetime. See DrupalCacheInterface::get().",
+ 'description' => "The time of this user's last post. This is used when the site has specified a minimum_cache_lifetime. See Drupal\Core\Cache\CacheBackendInterface::get().",
'type' => 'int',
'not null' => TRUE,
'default' => 0,
@@ -1668,6 +1697,70 @@ function system_update_8002() {
}
/**
+ * Adds {config} table for new Configuration system.
+ */
+function system_update_8003() {
+ // @todo Temporary.
+ if (db_table_exists('config')) {
+ db_drop_table('config');
+ }
+ db_create_table('config', array(
+ 'description' => 'Default active store for the configuration system.',
+ 'fields' => array(
+ 'name' => array(
+ 'description' => 'The identifier for the configuration entry, such as module.example (the name of the file, minus the file extension).',
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ 'default' => '',
+ ),
+ 'data' => array(
+ 'description' => 'The raw data for this configuration entry.',
+ 'type' => 'blob',
+ 'not null' => TRUE,
+ 'size' => 'big',
+ 'translatable' => TRUE,
+ ),
+ ),
+ 'primary key' => array('name'),
+ ));
+}
+
+/**
+ * Adds {file_managed}.langcode field.
+ *
+ * @see http://drupal.org/node/1454538
+ */
+function system_update_8004() {
+ $langcode_field = array(
+ 'description' => 'The {language}.langcode of this file.',
+ 'type' => 'varchar',
+ 'length' => 12,
+ 'not null' => TRUE,
+ 'default' => '',
+ );
+
+ // If a Drupal 7 contrib module already added a langcode field to support
+ // internationalization, keep it, but standardize the specification.
+ // Otherwise, add the field.
+ if (db_field_exists('file_managed', 'langcode')) {
+ // According to the documentation of db_change_field(), indeces using the
+ // field should be dropped first; if the contrib module created any indeces,
+ // it is its responsibility to drop them in an update function that runs
+ // before this one, which it can enforce via hook_update_dependencies().
+ db_change_field('file_managed', 'langcode', 'langcode', $langcode_field);
+ }
+ else {
+ // Files can be language-specific (e.g., a scanned document) or not (e.g.,
+ // a photograph). For a site being updated, Drupal does not have a way to
+ // determine which existing files are language-specific and in what
+ // language. Our best guess is to set all of them to LANGUAGE_NOT_SPECIFIED.
+ $langcode_field['initial'] = LANGUAGE_NOT_SPECIFIED;
+ db_add_field('file_managed', 'langcode', $langcode_field);
+ }
+}
+
+/**
* @} End of "defgroup updates-7.x-to-8.x"
* The next series of updates should start at 9000.
*/
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 7fc0141..07eacd2 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -374,6 +374,26 @@ function system_element_info() {
'#theme' => 'tel',
'#theme_wrappers' => array('form_element'),
);
+ $types['email'] = array(
+ '#input' => TRUE,
+ '#size' => 60,
+ '#maxlength' => EMAIL_MAX_LENGTH,
+ '#autocomplete_path' => FALSE,
+ '#process' => array('ajax_process_form'),
+ '#element_validate' => array('form_validate_email'),
+ '#theme' => 'email',
+ '#theme_wrappers' => array('form_element'),
+ );
+ $types['url'] = array(
+ '#input' => TRUE,
+ '#size' => 60,
+ '#maxlength' => 255,
+ '#autocomplete_path' => FALSE,
+ '#process' => array('ajax_process_form'),
+ '#element_validate' => array('form_validate_url'),
+ '#theme' => 'url',
+ '#theme_wrappers' => array('form_element'),
+ );
$types['machine_name'] = array(
'#input' => TRUE,
'#default_value' => NULL,
@@ -403,7 +423,7 @@ function system_element_info() {
'#input' => TRUE,
'#cols' => 60,
'#rows' => 5,
- '#resizable' => TRUE,
+ '#resizable' => 'vertical',
'#process' => array('ajax_process_form'),
'#theme' => 'textarea',
'#theme_wrappers' => array('form_element'),
@@ -1162,15 +1182,6 @@ function system_library_info() {
),
);
- // Drupal's resizable textarea.
- $libraries['drupal.textarea'] = array(
- 'title' => 'Drupal resizable textarea',
- 'version' => VERSION,
- 'js' => array(
- 'core/misc/textarea.js' => array('group' => JS_DEFAULT),
- ),
- );
-
// Drupal's autocomplete widget.
$libraries['drupal.autocomplete'] = array(
'title' => 'Drupal autocomplete',
@@ -1668,13 +1679,13 @@ function system_stream_wrappers() {
$wrappers = array(
'public' => array(
'name' => t('Public files'),
- 'class' => 'DrupalPublicStreamWrapper',
+ 'class' => 'Drupal\Core\StreamWrapper\PublicStream',
'description' => t('Public local files served by the webserver.'),
'type' => STREAM_WRAPPERS_LOCAL_NORMAL,
),
'temporary' => array(
'name' => t('Temporary files'),
- 'class' => 'DrupalTemporaryStreamWrapper',
+ 'class' => 'Drupal\Core\StreamWrapper\TemporaryStream',
'description' => t('Temporary local files for upload and previews.'),
'type' => STREAM_WRAPPERS_LOCAL_HIDDEN,
),
@@ -1684,7 +1695,7 @@ function system_stream_wrappers() {
if (variable_get('file_private_path', FALSE)) {
$wrappers['private'] = array(
'name' => t('Private files'),
- 'class' => 'DrupalPrivateStreamWrapper',
+ 'class' => 'Drupal\Core\StreamWrapper\PrivateStream',
'description' => t('Private local files served by Drupal.'),
'type' => STREAM_WRAPPERS_LOCAL_NORMAL,
);
@@ -1851,12 +1862,12 @@ function system_authorized_batch_process() {
function system_updater_info() {
return array(
'module' => array(
- 'class' => 'ModuleUpdater',
+ 'class' => 'Drupal\Core\Updater\Module',
'name' => t('Update modules'),
'weight' => 0,
),
'theme' => array(
- 'class' => 'ThemeUpdater',
+ 'class' => 'Drupal\Core\Updater\Theme',
'name' => t('Update themes'),
'weight' => 0,
),
@@ -2381,7 +2392,6 @@ function _system_rebuild_module_data() {
$modules[$profile] = new stdClass();
$modules[$profile]->name = $profile;
$modules[$profile]->uri = 'profiles/' . $profile . '/' . $profile . '.profile';
- $modules[$profile]->filename = $profile . '.profile';
// Install profile hooks are always executed last.
$modules[$profile]->weight = 1000;
@@ -2771,12 +2781,27 @@ function system_settings_form_submit($form, &$form_state) {
// Exclude unnecessary elements.
form_state_values_clean($form_state);
+ $config_objects = array();
foreach ($form_state['values'] as $key => $value) {
+ if (isset($form_state['config'][$key])) {
+ $config_name = $form_state['config'][$key]['name'];
+ $config_key = $form_state['config'][$key]['path'];
+ if (empty($config_objects[$config_name])) {
+ $config_objects[$config_name] = config($config_name);
+ }
+ if (!empty($config_objects[$config_name])) {
+ $config_objects[$config_name]->set($config_key, $value);
+ continue;
+ }
+ }
if (is_array($value) && isset($form_state['values']['array_filter'])) {
$value = array_keys(array_filter($value));
}
variable_set($key, $value);
}
+ foreach ($config_objects as $config) {
+ $config->save();
+ }
drupal_set_message(t('The configuration options have been saved.'));
}
diff --git a/core/modules/system/system.queue.inc b/core/modules/system/system.queue.inc
deleted file mode 100644
index c2a6b13..0000000
--- a/core/modules/system/system.queue.inc
+++ /dev/null
@@ -1,371 +0,0 @@
-name = $name;
- }
-
- public function createItem($data) {
- // During a Drupal 6.x to 8.x update, drupal_get_schema() does not contain
- // the queue table yet, so we cannot rely on drupal_write_record().
- $query = db_insert('queue')
- ->fields(array(
- 'name' => $this->name,
- 'data' => serialize($data),
- // We cannot rely on REQUEST_TIME because many items might be created
- // by a single request which takes longer than 1 second.
- 'created' => time(),
- ));
- return (bool) $query->execute();
- }
-
- public function numberOfItems() {
- return db_query('SELECT COUNT(item_id) FROM {queue} WHERE name = :name', array(':name' => $this->name))->fetchField();
- }
-
- public function claimItem($lease_time = 30) {
- // Claim an item by updating its expire fields. If claim is not successful
- // another thread may have claimed the item in the meantime. Therefore loop
- // until an item is successfully claimed or we are reasonably sure there
- // are no unclaimed items left.
- while (TRUE) {
- $item = db_query_range('SELECT data, item_id FROM {queue} q WHERE expire = 0 AND name = :name ORDER BY created ASC', 0, 1, array(':name' => $this->name))->fetchObject();
- if ($item) {
- // Try to update the item. Only one thread can succeed in UPDATEing the
- // same row. We cannot rely on REQUEST_TIME because items might be
- // claimed by a single consumer which runs longer than 1 second. If we
- // continue to use REQUEST_TIME instead of the current time(), we steal
- // time from the lease, and will tend to reset items before the lease
- // should really expire.
- $update = db_update('queue')
- ->fields(array(
- 'expire' => time() + $lease_time,
- ))
- ->condition('item_id', $item->item_id)
- ->condition('expire', 0);
- // If there are affected rows, this update succeeded.
- if ($update->execute()) {
- $item->data = unserialize($item->data);
- return $item;
- }
- }
- else {
- // No items currently available to claim.
- return FALSE;
- }
- }
- }
-
- public function releaseItem($item) {
- $update = db_update('queue')
- ->fields(array(
- 'expire' => 0,
- ))
- ->condition('item_id', $item->item_id);
- return $update->execute();
- }
-
- public function deleteItem($item) {
- db_delete('queue')
- ->condition('item_id', $item->item_id)
- ->execute();
- }
-
- public function createQueue() {
- // All tasks are stored in a single database table (which is created when
- // Drupal is first installed) so there is nothing we need to do to create
- // a new queue.
- }
-
- public function deleteQueue() {
- db_delete('queue')
- ->condition('name', $this->name)
- ->execute();
- }
-}
-
-/**
- * Static queue implementation.
- *
- * This allows "undelayed" variants of processes relying on the Queue
- * interface. The queue data resides in memory. It should only be used for
- * items that will be queued and dequeued within a given page request.
- */
-class MemoryQueue implements DrupalQueueInterface {
- /**
- * The queue data.
- *
- * @var array
- */
- protected $queue;
-
- /**
- * Counter for item ids.
- *
- * @var int
- */
- protected $id_sequence;
-
- public function __construct($name) {
- $this->queue = array();
- $this->id_sequence = 0;
- }
-
- public function createItem($data) {
- $item = new stdClass();
- $item->item_id = $this->id_sequence++;
- $item->data = $data;
- $item->created = time();
- $item->expire = 0;
- $this->queue[$item->item_id] = $item;
- }
-
- public function numberOfItems() {
- return count($this->queue);
- }
-
- public function claimItem($lease_time = 30) {
- foreach ($this->queue as $key => $item) {
- if ($item->expire == 0) {
- $item->expire = time() + $lease_time;
- $this->queue[$key] = $item;
- return $item;
- }
- }
- return FALSE;
- }
-
- public function deleteItem($item) {
- unset($this->queue[$item->item_id]);
- }
-
- public function releaseItem($item) {
- if (isset($this->queue[$item->item_id]) && $this->queue[$item->item_id]->expire != 0) {
- $this->queue[$item->item_id]->expire = 0;
- return TRUE;
- }
- return FALSE;
- }
-
- public function createQueue() {
- // Nothing needed here.
- }
-
- public function deleteQueue() {
- $this->queue = array();
- $this->id_sequence = 0;
- }
-}
-
-/**
- * @} End of "defgroup queue".
- */
diff --git a/core/modules/system/system.test b/core/modules/system/system.test
index 64774c4..9287d16 100644
--- a/core/modules/system/system.test
+++ b/core/modules/system/system.test
@@ -132,8 +132,6 @@ class ModuleTestCase extends DrupalWebTestCase {
* Test module enabling/disabling functionality.
*/
class EnableDisableTestCase extends ModuleTestCase {
- protected $profile = 'testing';
-
public static function getInfo() {
return array(
'name' => 'Enable/disable modules',
@@ -154,7 +152,26 @@ class EnableDisableTestCase extends ModuleTestCase {
unset($modules[$name]);
}
}
- $this->assertTrue(count($modules), t('Found @count core modules that we can try to enable in this test.', array('@count' => count($modules))));
+
+ // Throughout this test, some modules may be automatically enabled (due to
+ // dependencies). We'll keep track of them in an array, so we can handle
+ // them separately.
+ $automatically_enabled = array();
+
+ // Remove already enabled modules (via installation profile).
+ // @todo Remove this after removing all dependencies from Testing profile.
+ foreach (module_list() as $dependency) {
+ // Exclude required modules. Only installation profile "suggestions" can
+ // be disabled and uninstalled.
+ if (isset($modules[$dependency])) {
+ $automatically_enabled[$dependency] = TRUE;
+ }
+ }
+
+ $this->assertTrue(count($modules), t('Found @count modules that can be enabled: %modules', array(
+ '@count' => count($modules),
+ '%modules' => implode(', ', array_keys($modules)),
+ )));
// Enable the dblog module first, since we will be asserting the presence
// of log messages throughout the test.
@@ -166,11 +183,6 @@ class EnableDisableTestCase extends ModuleTestCase {
// will display messages via drupal_set_message().
variable_set('test_verbose_module_hooks', TRUE);
- // Throughout this test, some modules may be automatically enabled (due to
- // dependencies). We'll keep track of them in an array, so we can handle
- // them separately.
- $automatically_enabled = array();
-
// Go through each module in the list and try to enable it (unless it was
// already enabled automatically due to a dependency).
foreach ($modules as $name => $module) {
@@ -443,6 +455,8 @@ class ModuleDependencyTestCase extends ModuleTestCase {
* Tests enabling a module that depends on a module which fails hook_requirements().
*/
function testEnableRequirementsFailureDependency() {
+ module_enable(array('comment'));
+
$this->assertModules(array('requirements1_test'), FALSE);
$this->assertModules(array('requirements2_test'), FALSE);
@@ -472,9 +486,12 @@ class ModuleDependencyTestCase extends ModuleTestCase {
$this->resetAll();
$this->assertModules(array('module_test'), TRUE);
variable_set('dependency_test', 'dependency');
- // module_test creates a dependency chain: forum depends on poll, which
- // depends on php. The correct enable order is, php, poll, forum.
- $expected_order = array('php', 'poll', 'forum');
+ // module_test creates a dependency chain:
+ // - forum depends on taxonomy, comment, and poll (via module_test)
+ // - taxonomy depends on options
+ // - poll depends on php (via module_test)
+ // The correct enable order is:
+ $expected_order = array('comment', 'options', 'taxonomy', 'php', 'poll', 'forum');
// Enable the modules through the UI, verifying that the dependency chain
// is correct.
@@ -482,14 +499,17 @@ class ModuleDependencyTestCase extends ModuleTestCase {
$edit['modules[Core][forum][enable]'] = 'forum';
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
$this->assertModules(array('forum'), FALSE);
- $this->assertText(t('You must enable the Poll, PHP Filter modules to install Forum.'), t('Dependency chain created.'));
+ $this->assertText(t('You must enable the Taxonomy, Options, Comment, Poll, PHP Filter modules to install Forum.'));
+ $edit['modules[Core][options][enable]'] = 'options';
+ $edit['modules[Core][taxonomy][enable]'] = 'taxonomy';
+ $edit['modules[Core][comment][enable]'] = 'comment';
$edit['modules[Core][poll][enable]'] = 'poll';
$edit['modules[Core][php][enable]'] = 'php';
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
- $this->assertModules(array('forum', 'poll', 'php'), TRUE);
+ $this->assertModules(array('forum', 'poll', 'php', 'comment', 'taxonomy', 'options'), TRUE);
// Check the actual order which is saved by module_test_modules_enabled().
- $this->assertIdentical(variable_get('test_module_enable_order', FALSE), $expected_order, t('Modules enabled in the correct order.'));
+ $this->assertIdentical(variable_get('test_module_enable_order', array()), $expected_order);
}
/**
@@ -499,6 +519,7 @@ class ModuleDependencyTestCase extends ModuleTestCase {
// Enable the forum module.
$edit = array('modules[Core][forum][enable]' => 'forum');
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
+ $this->drupalPost(NULL, array(), t('Continue'));
$this->assertModules(array('forum'), TRUE);
// Disable forum and comment. Both should now be installed but disabled.
@@ -874,10 +895,13 @@ class AccessDeniedTestCase extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp();
+ parent::setUp(array('block'));
// Create an administrative user.
$this->admin_user = $this->drupalCreateUser(array('access administration pages', 'administer site configuration', 'administer blocks'));
+
+ user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access user profiles'));
+ user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID, array('access user profiles'));
}
function testAccessDenied() {
@@ -885,34 +909,34 @@ class AccessDeniedTestCase extends DrupalWebTestCase {
$this->assertText(t('Access denied'), t('Found the default 403 page'));
$this->assertResponse(403);
+ // Use a custom 403 page.
$this->drupalLogin($this->admin_user);
$edit = array(
- 'title' => $this->randomName(10),
- 'body' => array(LANGUAGE_NONE => array(array('value' => $this->randomName(100)))),
+ 'site_403' => 'user/' . $this->admin_user->uid,
);
- $node = $this->drupalCreateNode($edit);
-
- // Use a custom 403 page.
- $this->drupalPost('admin/config/system/site-information', array('site_403' => 'node/' . $node->nid), t('Save configuration'));
+ $this->drupalPost('admin/config/system/site-information', $edit, t('Save configuration'));
- $this->drupalLogout();
- $this->drupalGet('admin');
- $this->assertText($node->title, t('Found the custom 403 page'));
+ // Enable the user login block.
+ $edit = array(
+ 'blocks[user_login][region]' => 'sidebar_first',
+ );
+ $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
// Logout and check that the user login block is shown on custom 403 pages.
$this->drupalLogout();
-
$this->drupalGet('admin');
- $this->assertText($node->title, t('Found the custom 403 page'));
+ $this->assertText($this->admin_user->name, t('Found the custom 403 page'));
$this->assertText(t('User login'), t('Blocks are shown on the custom 403 page'));
// Log back in and remove the custom 403 page.
$this->drupalLogin($this->admin_user);
- $this->drupalPost('admin/config/system/site-information', array('site_403' => ''), t('Save configuration'));
+ $edit = array(
+ 'site_403' => '',
+ );
+ $this->drupalPost('admin/config/system/site-information', $edit, t('Save configuration'));
// Logout and check that the user login block is shown on default 403 pages.
$this->drupalLogout();
-
$this->drupalGet('admin');
$this->assertText(t('Access denied'), t('Found the default 403 page'));
$this->assertResponse(403);
@@ -939,9 +963,6 @@ class AccessDeniedTestCase extends DrupalWebTestCase {
class PageNotFoundTestCase extends DrupalWebTestCase {
protected $admin_user;
- /**
- * Implement getInfo().
- */
public static function getInfo() {
return array(
'name' => '404 functionality',
@@ -950,32 +971,29 @@ class PageNotFoundTestCase extends DrupalWebTestCase {
);
}
- /**
- * Implement setUp().
- */
function setUp() {
parent::setUp();
// Create an administrative user.
$this->admin_user = $this->drupalCreateUser(array('administer site configuration'));
- $this->drupalLogin($this->admin_user);
+
+ user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access user profiles'));
+ user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID, array('access user profiles'));
}
function testPageNotFound() {
+ $this->drupalLogin($this->admin_user);
$this->drupalGet($this->randomName(10));
$this->assertText(t('Page not found'), t('Found the default 404 page'));
+ // Use a custom 404 page.
$edit = array(
- 'title' => $this->randomName(10),
- 'body' => array(LANGUAGE_NONE => array(array('value' => $this->randomName(100)))),
+ 'site_404' => 'user/' . $this->admin_user->uid,
);
- $node = $this->drupalCreateNode($edit);
-
- // Use a custom 404 page.
- $this->drupalPost('admin/config/system/site-information', array('site_404' => 'node/' . $node->nid), t('Save configuration'));
+ $this->drupalPost('admin/config/system/site-information', $edit, t('Save configuration'));
$this->drupalGet($this->randomName(10));
- $this->assertText($node->title, t('Found the custom 404 page'));
+ $this->assertText($this->admin_user->name, t('Found the custom 404 page'));
}
}
@@ -994,7 +1012,10 @@ class SiteMaintenanceTestCase extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp();
+ parent::setUp(array('node'));
+
+ // Configure 'node' as front page.
+ variable_set('site_frontpage', 'node');
// Create a user allowed to access site in maintenance mode.
$this->user = $this->drupalCreateUser(array('access site in maintenance mode'));
@@ -1295,7 +1316,9 @@ class PageTitleFiltering extends DrupalWebTestCase {
* Implement setUp().
*/
function setUp() {
- parent::setUp();
+ parent::setUp(array('node'));
+
+ $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
$this->content_user = $this->drupalCreateUser(array('create page content', 'access content', 'administer themes', 'administer site configuration'));
$this->drupalLogin($this->content_user);
@@ -1326,7 +1349,7 @@ class PageTitleFiltering extends DrupalWebTestCase {
drupal_set_title($title, PASS_THROUGH);
$this->assertTrue(strpos(drupal_get_title(), '') !== FALSE, t('Tags in title are not converted to entities when $output is PASS_THROUGH.'));
// Generate node content.
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$edit = array(
"title" => '!SimpleTest! ' . $title . $this->randomName(20),
"body[$langcode][0][value]" => '!SimpleTest! test body' . $this->randomName(200),
@@ -1394,13 +1417,15 @@ class FrontPageTestCase extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('system_test');
+ parent::setUp(array('node', 'system_test'));
// Create admin user, log in admin user, and create one node.
$this->admin_user = $this->drupalCreateUser(array('access content', 'administer site configuration'));
$this->drupalLogin($this->admin_user);
$this->node_path = "node/" . $this->drupalCreateNode(array('promote' => 1))->nid;
+ // Configure 'node' as front page.
+ variable_set('site_frontpage', 'node');
// Enable front page logging in system_test.module.
variable_set('front_page_output', 1);
}
@@ -1436,8 +1461,6 @@ class FrontPageTestCase extends DrupalWebTestCase {
}
class SystemBlockTestCase extends DrupalWebTestCase {
- protected $profile = 'testing';
-
public static function getInfo() {
return array(
'name' => 'Block functionality',
@@ -1517,20 +1540,18 @@ class SystemMainContentFallback extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp('system_test');
+ parent::setUp(array('block', 'system_test'));
// Create and login admin user.
$this->admin_user = $this->drupalCreateUser(array(
'access administration pages',
'administer site configuration',
'administer modules',
- 'administer blocks',
- 'administer nodes',
));
$this->drupalLogin($this->admin_user);
// Create a web user.
- $this->web_user = $this->drupalCreateUser(array('access user profiles', 'access content'));
+ $this->web_user = $this->drupalCreateUser(array('access user profiles'));
}
/**
@@ -1538,10 +1559,6 @@ class SystemMainContentFallback extends DrupalWebTestCase {
*/
function testMainContentFallback() {
$edit = array();
- // Disable the dashboard module, which depends on the block module.
- $edit['modules[Core][dashboard][enable]'] = FALSE;
- $this->drupalPost('admin/modules', $edit, t('Save configuration'));
- $this->assertText(t('The configuration options have been saved.'), t('Modules status has been updated.'));
// Disable the block module.
$edit['modules[Core][block][enable]'] = FALSE;
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
@@ -1589,8 +1606,6 @@ class SystemMainContentFallback extends DrupalWebTestCase {
* Tests for the theme interface functionality.
*/
class SystemThemeFunctionalTest extends DrupalWebTestCase {
- protected $profile = 'testing';
-
public static function getInfo() {
return array(
'name' => 'Theme interface functionality',
@@ -1811,98 +1826,6 @@ class SystemThemeFunctionalTest extends DrupalWebTestCase {
}
}
-
-/**
- * Test the basic queue functionality.
- */
-class QueueTestCase extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Queue functionality',
- 'description' => 'Queues and dequeues a set of items to check the basic queue functionality.',
- 'group' => 'System',
- );
- }
-
- /**
- * Queues and dequeues a set of items to check the basic queue functionality.
- */
- function testQueue() {
- // Create two queues.
- $queue1 = DrupalQueue::get($this->randomName());
- $queue1->createQueue();
- $queue2 = DrupalQueue::get($this->randomName());
- $queue2->createQueue();
-
- // Create four items.
- $data = array();
- for ($i = 0; $i < 4; $i++) {
- $data[] = array($this->randomName() => $this->randomName());
- }
-
- // Queue items 1 and 2 in the queue1.
- $queue1->createItem($data[0]);
- $queue1->createItem($data[1]);
-
- // Retrieve two items from queue1.
- $items = array();
- $new_items = array();
-
- $items[] = $item = $queue1->claimItem();
- $new_items[] = $item->data;
-
- $items[] = $item = $queue1->claimItem();
- $new_items[] = $item->data;
-
- // First two dequeued items should match the first two items we queued.
- $this->assertEqual($this->queueScore($data, $new_items), 2, t('Two items matched'));
-
- // Add two more items.
- $queue1->createItem($data[2]);
- $queue1->createItem($data[3]);
-
- $this->assertTrue($queue1->numberOfItems(), t('Queue 1 is not empty after adding items.'));
- $this->assertFalse($queue2->numberOfItems(), t('Queue 2 is empty while Queue 1 has items'));
-
- $items[] = $item = $queue1->claimItem();
- $new_items[] = $item->data;
-
- $items[] = $item = $queue1->claimItem();
- $new_items[] = $item->data;
-
- // All dequeued items should match the items we queued exactly once,
- // therefore the score must be exactly 4.
- $this->assertEqual($this->queueScore($data, $new_items), 4, t('Four items matched'));
-
- // There should be no duplicate items.
- $this->assertEqual($this->queueScore($new_items, $new_items), 4, t('Four items matched'));
-
- // Delete all items from queue1.
- foreach ($items as $item) {
- $queue1->deleteItem($item);
- }
-
- // Check that both queues are empty.
- $this->assertFalse($queue1->numberOfItems(), t('Queue 1 is empty'));
- $this->assertFalse($queue2->numberOfItems(), t('Queue 2 is empty'));
- }
-
- /**
- * This function returns the number of equal items in two arrays.
- */
- function queueScore($items, $new_items) {
- $score = 0;
- foreach ($items as $item) {
- foreach ($new_items as $new_item) {
- if ($item === $new_item) {
- $score++;
- }
- }
- }
- return $score;
- }
-}
-
/**
* Test token replacement in strings.
*/
@@ -2686,68 +2609,3 @@ class SystemIndexPhpTest extends DrupalWebTestCase {
$this->assertResponse(404, t("Make sure index.php/user returns a 'page not found'."));
}
}
-/**
- * Tests uuid.inc and related functions.
- */
-class UuidUnitTestCase extends DrupalUnitTestCase {
-
- /**
- * The UUID object to be used for generating UUIDs.
- *
- * @var Uuid
- */
- protected $uuid;
-
- public static function getInfo() {
- return array(
- 'name' => 'UUID handling',
- 'description' => "Test the handling of Universally Unique IDentifiers (UUIDs).",
- 'group' => 'System',
- );
- }
-
- public function setUp() {
- // Initiate the generator. This will lazy-load uuid.inc.
- $this->uuid = new Uuid();
- parent::setUp();
- }
-
- /**
- * Test generating a UUID.
- */
- public function testGenerateUuid() {
- $uuid = $this->uuid->generate();
- $this->assertTrue($this->uuid->isValid($uuid), 'UUID generation works.');
- }
-
- /**
- * Test that generated UUIDs are unique.
- */
- public function testUuidIsUnique() {
- $uuid1 = $this->uuid->generate();
- $uuid2 = $this->uuid->generate();
- $this->assertNotEqual($uuid1, $uuid2, 'Same UUID was not generated twice.');
- }
-
- /**
- * Test UUID validation.
- */
- function testUuidValidation() {
- // These valid UUIDs.
- $uuid_fqdn = '6ba7b810-9dad-11d1-80b4-00c04fd430c8';
- $uuid_min = '00000000-0000-0000-0000-000000000000';
- $uuid_max = 'ffffffff-ffff-ffff-ffff-ffffffffffff';
-
- $this->assertTrue($this->uuid->isValid($uuid_fqdn), t('FQDN namespace UUID (@uuid) is valid', array('@uuid' => $uuid_fqdn)));
- $this->assertTrue($this->uuid->isValid($uuid_min), t('Minimum UUID value (@uuid) is valid', array('@uuid' => $uuid_min)));
- $this->assertTrue($this->uuid->isValid($uuid_max), t('Maximum UUID value (@uuid) is valid', array('@uuid' => $uuid_max)));
-
- // These are invalid UUIDs.
- $invalid_format = '0ab26e6b-f074-4e44-9da-601205fa0e976';
- $invalid_length = '0ab26e6b-f074-4e44-9daf-1205fa0e9761f';
-
- $this->assertFalse($this->uuid->isValid($invalid_format), t('@uuid is not a valid UUID', array('@uuid' => $invalid_format)));
- $this->assertFalse($this->uuid->isValid($invalid_length), t('@uuid is not a valid UUID', array('@uuid' => $invalid_length)));
-
- }
-}
diff --git a/core/modules/system/system.updater.inc b/core/modules/system/system.updater.inc
deleted file mode 100644
index 84c1752..0000000
--- a/core/modules/system/system.updater.inc
+++ /dev/null
@@ -1,146 +0,0 @@
-name)) {
- $relative_path = dirname($relative_path);
- }
- else {
- $relative_path = 'sites/all/modules';
- }
- return DRUPAL_ROOT . '/' . $relative_path;
- }
-
- public function isInstalled() {
- return (bool) drupal_get_path('module', $this->name);
- }
-
- public static function canUpdateDirectory($directory) {
- if (file_scan_directory($directory, '/.*\.module$/')) {
- return TRUE;
- }
- return FALSE;
- }
-
- public static function canUpdate($project_name) {
- return (bool) drupal_get_path('module', $project_name);
- }
-
- /**
- * Return available database schema updates one a new version is installed.
- */
- public function getSchemaUpdates() {
- require_once DRUPAL_ROOT . '/core/includes/install.inc';
- require_once DRUPAL_ROOT . '/core/includes/update.inc';
-
- if (_update_get_project_type($project) != 'module') {
- return array();
- }
- module_load_include('install', $project);
-
- if (!$updates = drupal_get_schema_versions($project)) {
- return array();
- }
- $updates_to_run = array();
- $modules_with_updates = update_get_update_list();
- if ($updates = $modules_with_updates[$project]) {
- if ($updates['start']) {
- return $updates['pending'];
- }
- }
- return array();
- }
-
- public function postInstallTasks() {
- return array(
- l(t('Enable newly added modules'), 'admin/modules'),
- l(t('Administration pages'), 'admin'),
- );
- }
-
- public function postUpdateTasks() {
- // We don't want to check for DB updates here, we do that once for all
- // updated modules on the landing page.
- }
-
-}
-
-/**
- * Class for updating themes using FileTransfer classes via authorize.php.
- */
-class ThemeUpdater extends Updater implements DrupalUpdaterInterface {
-
- /**
- * Return the directory where a theme should be installed.
- *
- * If the theme is already installed, drupal_get_path() will return
- * a valid path and we should install it there (although we need to use an
- * absolute path, so we prepend DRUPAL_ROOT). If we're installing a new
- * theme, we always want it to go into sites/all/themes, since that's
- * where all the documentation recommends users install their themes, and
- * there's no way that can conflict on a multi-site installation, since
- * the Update manager won't let you install a new theme if it's already
- * found on your system, and if there was a copy in sites/all, we'd see it.
- */
- public function getInstallDirectory() {
- if ($relative_path = drupal_get_path('theme', $this->name)) {
- $relative_path = dirname($relative_path);
- }
- else {
- $relative_path = 'sites/all/themes';
- }
- return DRUPAL_ROOT . '/' . $relative_path;
- }
-
- public function isInstalled() {
- return (bool) drupal_get_path('theme', $this->name);
- }
-
- static function canUpdateDirectory($directory) {
- // This is a lousy test, but don't know how else to confirm it is a theme.
- if (file_scan_directory($directory, '/.*\.module$/')) {
- return FALSE;
- }
- return TRUE;
- }
-
- public static function canUpdate($project_name) {
- return (bool) drupal_get_path('theme', $project_name);
- }
-
- public function postInstall() {
- // Update the system table.
- clearstatcache();
- system_rebuild_theme_data();
-
- }
-
- public function postInstallTasks() {
- return array(
- l(t('Enable newly added themes'), 'admin/appearance'),
- l(t('Administration pages'), 'admin'),
- );
- }
-}
diff --git a/core/modules/taxonomy/taxonomy.admin.inc b/core/modules/taxonomy/taxonomy.admin.inc
index bf8a528..beb87f9 100644
--- a/core/modules/taxonomy/taxonomy.admin.inc
+++ b/core/modules/taxonomy/taxonomy.admin.inc
@@ -117,6 +117,10 @@ function taxonomy_form_vocabulary($form, &$form_state, $edit = array()) {
'description' => '',
'hierarchy' => TAXONOMY_HIERARCHY_DISABLED,
'weight' => 0,
+ // Default the new vocabulary to the site's default language. This is
+ // the most likely default value until we have better flexible settings.
+ // @todo See http://drupal.org/node/258785 and followups.
+ 'langcode' => language_default()->langcode,
);
foreach ($defaults as $key => $value) {
if (!isset($vocabulary->$key)) {
@@ -659,6 +663,10 @@ function taxonomy_form_term($form, &$form_state, $edit = array(), $vocabulary =
'vocabulary_machine_name' => isset($vocabulary) ? $vocabulary->machine_name : NULL,
'tid' => NULL,
'weight' => 0,
+ // Default the new term to the site's default language. This is the most
+ // likely default value until we have better flexible settings.
+ // @todo See http://drupal.org/node/258785 and followups.
+ 'langcode' => language_default()->langcode,
);
foreach ($defaults as $key => $value) {
if (!isset($term->$key)) {
diff --git a/core/modules/taxonomy/taxonomy.install b/core/modules/taxonomy/taxonomy.install
index 3e07259..14b6956 100644
--- a/core/modules/taxonomy/taxonomy.install
+++ b/core/modules/taxonomy/taxonomy.install
@@ -39,6 +39,13 @@ function taxonomy_schema() {
'default' => 0,
'description' => 'The {taxonomy_vocabulary}.vid of the vocabulary to which the term is assigned.',
),
+ 'langcode' => array(
+ 'description' => 'The {language}.langcode of this term.',
+ 'type' => 'varchar',
+ 'length' => 12,
+ 'not null' => TRUE,
+ 'default' => '',
+ ),
'name' => array(
'type' => 'varchar',
'length' => 255,
@@ -120,6 +127,13 @@ function taxonomy_schema() {
'not null' => TRUE,
'description' => 'Primary Key: Unique vocabulary ID.',
),
+ 'langcode' => array(
+ 'description' => 'The {language}.langcode of this vocabulary.',
+ 'type' => 'varchar',
+ 'length' => 12,
+ 'not null' => TRUE,
+ 'default' => '',
+ ),
'name' => array(
'type' => 'varchar',
'length' => 255,
@@ -245,4 +259,44 @@ function taxonomy_field_schema($field) {
*/
function taxonomy_update_8000() {
db_drop_field('taxonomy_vocabulary', 'module');
-}
\ No newline at end of file
+}
+
+/**
+ * Adds langcode field to {taxonomy_term_data} and {taxonomy_vocabulary}.
+ *
+ * @see http://drupal.org/node/1454538
+ */
+function taxonomy_update_8001() {
+ $descriptions = array(
+ 'taxonomy_term_data' => 'The {language}.langcode of this term.',
+ 'taxonomy_vocabulary' => 'The {language}.langcode of this vocabulary.',
+ );
+ foreach ($descriptions as $table => $description) {
+ $langcode_field = array(
+ 'description' => $description,
+ 'type' => 'varchar',
+ 'length' => 12,
+ 'not null' => TRUE,
+ 'default' => '',
+ );
+
+ // If a Drupal 7 contrib module already added a langcode field to support
+ // internationalization, keep it, but standardize the specification.
+ // Otherwise, add the field.
+ if (db_field_exists($table, 'langcode')) {
+ // According to the documentation of db_change_field(), indeces using the
+ // field should be dropped first; if the contrib module created any
+ // indeces, it is its responsibility to drop them in an update function
+ // that runs before this one, which it can enforce via
+ // hook_update_dependencies().
+ db_change_field($table, 'langcode', 'langcode', $langcode_field);
+ }
+ else {
+ // When updating from a site that did not already have taxonomy
+ // internationalization, initialize all existing vocabularies and terms as
+ // being in the site's default language.
+ $langcode_field['initial'] = language_default()->langcode;
+ db_add_field($table, 'langcode', $langcode_field);
+ }
+ }
+}
diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index eac6bed..23a0a6b 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -434,6 +434,7 @@ function taxonomy_admin_vocabulary_title_callback($vocabulary) {
* - vid: The ID of the vocabulary.
* - name: The human-readable name of the vocabulary.
* - machine_name: The machine name of the vocabulary.
+ * - langcode: The language code of the vocabulary.
* - description: (optional) The vocabulary's description.
* - hierarchy: The hierarchy level of the vocabulary.
* - module: (optional) The module altering the vocabulary.
@@ -638,6 +639,7 @@ function taxonomy_check_vocabulary_hierarchy($vocabulary, $changed_term) {
* The taxonomy term object with the following properties:
* - vid: The ID of the vocabulary the term is assigned to.
* - name: The name of the term.
+ * - langcode: The language code of the term.
* - tid: (optional) The unique ID for the term being saved. If $term->tid is
* empty or omitted, a new term will be inserted.
* - description: (optional) The term's description.
@@ -1829,6 +1831,7 @@ function taxonomy_field_presave($entity_type, $entity, $field, $instance, $langc
if ($item['tid'] == 'autocreate') {
$term = (object) $item;
unset($term->tid);
+ $term->langcode = $langcode;
taxonomy_term_save($term);
$items[$delta]['tid'] = $term->tid;
}
diff --git a/core/modules/taxonomy/taxonomy.pages.inc b/core/modules/taxonomy/taxonomy.pages.inc
index 4bdcbc5..6994b6e 100644
--- a/core/modules/taxonomy/taxonomy.pages.inc
+++ b/core/modules/taxonomy/taxonomy.pages.inc
@@ -106,6 +106,13 @@ function taxonomy_term_feed($term) {
* @see taxonomy_field_widget_info()
*/
function taxonomy_autocomplete($field_name, $tags_typed = '') {
+ // If the request has a '/' in the search text, then the menu system will have
+ // split it into multiple arguments, recover the intended $tags_typed.
+ $args = func_get_args();
+ // Shift off the $field_name argument.
+ array_shift($args);
+ $tags_typed = implode('/', $args);
+
// Make sure the field exists and is a taxonomy field.
if (!($field = field_info_field($field_name)) || $field['type'] !== 'taxonomy_term_reference') {
// Error string. The JavaScript handler will realize this is not JSON and
diff --git a/core/modules/taxonomy/taxonomy.test b/core/modules/taxonomy/taxonomy.test
index b262b86..de50f2a 100644
--- a/core/modules/taxonomy/taxonomy.test
+++ b/core/modules/taxonomy/taxonomy.test
@@ -9,6 +9,19 @@
* Class with common helper methods.
*/
class TaxonomyWebTestCase extends DrupalWebTestCase {
+ function setUp() {
+ $modules = func_get_args();
+ if (isset($modules[0]) && is_array($modules[0])) {
+ $modules = $modules[0];
+ }
+ $modules[] = 'taxonomy';
+ parent::setUp($modules);
+
+ // Create Basic page and Article node types.
+ if ($this->profile != 'standard') {
+ $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
+ }
+ }
/**
* Returns a new vocabulary with random properties.
@@ -19,6 +32,7 @@ class TaxonomyWebTestCase extends DrupalWebTestCase {
$vocabulary->name = $this->randomName();
$vocabulary->description = $this->randomName();
$vocabulary->machine_name = drupal_strtolower($this->randomName());
+ $vocabulary->langcode = LANGUAGE_NOT_SPECIFIED;
$vocabulary->help = '';
$vocabulary->nodes = array('article' => 'article');
$vocabulary->weight = mt_rand(0, 10);
@@ -36,6 +50,7 @@ class TaxonomyWebTestCase extends DrupalWebTestCase {
// Use the first available text format.
$term->format = db_query_range('SELECT format FROM {filter_format}', 0, 1)->fetchField();
$term->vid = $vocabulary->vid;
+ $term->langcode = LANGUAGE_NOT_SPECIFIED;
taxonomy_term_save($term);
return $term;
}
@@ -191,7 +206,7 @@ class TaxonomyVocabularyUnitTest extends TaxonomyWebTestCase {
}
function setUp() {
- parent::setUp('taxonomy', 'field_test');
+ parent::setUp(array('field_test'));
$admin_user = $this->drupalCreateUser(array('create article content', 'administer taxonomy'));
$this->drupalLogin($admin_user);
$this->vocabulary = $this->createVocabulary();
@@ -475,6 +490,7 @@ class TaxonomyTermUnitTest extends TaxonomyWebTestCase {
* Test for legacy node bug.
*/
class TaxonomyLegacyTestCase extends TaxonomyWebTestCase {
+ protected $profile = 'standard';
public static function getInfo() {
return array(
@@ -485,7 +501,7 @@ class TaxonomyLegacyTestCase extends TaxonomyWebTestCase {
}
function setUp() {
- parent::setUp('taxonomy');
+ parent::setUp();
$this->admin_user = $this->drupalCreateUser(array('administer taxonomy', 'administer nodes', 'bypass node access'));
$this->drupalLogin($this->admin_user);
}
@@ -495,7 +511,7 @@ class TaxonomyLegacyTestCase extends TaxonomyWebTestCase {
*/
function testTaxonomyLegacyNode() {
// Posts an article with a taxonomy term and a date prior to 1970.
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$edit = array();
$edit['title'] = $this->randomName();
$edit['date'] = '1969-01-01 00:00:00 -0500';
@@ -522,7 +538,7 @@ class TaxonomyTermTestCase extends TaxonomyWebTestCase {
}
function setUp() {
- parent::setUp('taxonomy');
+ parent::setUp();
$this->admin_user = $this->drupalCreateUser(array('administer taxonomy', 'bypass node access'));
$this->drupalLogin($this->admin_user);
$this->vocabulary = $this->createVocabulary();
@@ -603,7 +619,7 @@ class TaxonomyTermTestCase extends TaxonomyWebTestCase {
// Post an article.
$edit = array();
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$edit["title"] = $this->randomName();
$edit["body[$langcode][0][value]"] = $this->randomName();
$edit[$this->instance['field_name'] . '[' . $langcode .'][]'] = $term1->tid;
@@ -635,8 +651,7 @@ class TaxonomyTermTestCase extends TaxonomyWebTestCase {
// Enable tags in the vocabulary.
$instance = $this->instance;
$instance['widget'] = array('type' => 'taxonomy_autocomplete');
- $instance['bundle'] = 'page';
- field_create_instance($instance);
+ field_update_instance($instance);
$terms = array(
'term1' => $this->randomName(),
'term2' => $this->randomName(),
@@ -645,7 +660,7 @@ class TaxonomyTermTestCase extends TaxonomyWebTestCase {
);
$edit = array();
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$edit["title"] = $this->randomName();
$edit["body[$langcode][0][value]"] = $this->randomName();
// Insert the terms in a comma separated list. Vocabulary 1 is a
@@ -653,7 +668,7 @@ class TaxonomyTermTestCase extends TaxonomyWebTestCase {
$edit[$instance['field_name'] . "[$langcode]"] = drupal_implode_tags($terms);
// Preview and verify the terms appear but are not created.
- $this->drupalPost('node/add/page', $edit, t('Preview'));
+ $this->drupalPost('node/add/article', $edit, t('Preview'));
foreach ($terms as $term) {
$this->assertText($term, t('The term appears on the node preview'));
}
@@ -661,11 +676,11 @@ class TaxonomyTermTestCase extends TaxonomyWebTestCase {
$this->assertTrue(empty($tree), t('The terms are not created on preview.'));
// taxonomy.module does not maintain its static caches.
- drupal_static_reset();
+ taxonomy_terms_static_reset();
// Save, creating the terms.
- $this->drupalPost('node/add/page', $edit, t('Save'));
- $this->assertRaw(t('@type %title has been created.', array('@type' => t('Basic page'), '%title' => $edit["title"])), t('The node was created successfully'));
+ $this->drupalPost('node/add/article', $edit, t('Save'));
+ $this->assertRaw(t('@type %title has been created.', array('@type' => t('Article'), '%title' => $edit["title"])), t('The node was created successfully'));
foreach ($terms as $term) {
$this->assertText($term, t('The term was saved and appears on the node page'));
}
@@ -717,6 +732,58 @@ class TaxonomyTermTestCase extends TaxonomyWebTestCase {
}
/**
+ * Tests term autocompletion edge cases with slashes in the names.
+ */
+ function testTermAutocompletion() {
+ // Add a term with a slash in the name.
+ $first_term = $this->createTerm($this->vocabulary);
+ $first_term->name = '10/16/2011';
+ taxonomy_term_save($first_term);
+ // Add another term that differs after the slash character.
+ $second_term = $this->createTerm($this->vocabulary);
+ $second_term->name = '10/17/2011';
+ taxonomy_term_save($second_term);
+ // Add another term that has both a comma and a slash character.
+ $third_term = $this->createTerm($this->vocabulary);
+ $third_term->name = 'term with, a comma and / a slash';
+ taxonomy_term_save($third_term);
+
+ // Try to autocomplete a term name that matches both terms.
+ // We should get both term in a json encoded string.
+ $input = '10/';
+ $path = 'taxonomy/autocomplete/taxonomy_';
+ $path .= $this->vocabulary->machine_name . '/' . $input;
+ // The result order is not guaranteed, so check each term separately.
+ $url = url($path, array('absolute' => TRUE));
+ $result = drupal_http_request($url);
+ $data = drupal_json_decode($result->data);
+ $this->assertEqual($data[$first_term->name], check_plain($first_term->name), 'Autocomplete returned the first matching term');
+ $this->assertEqual($data[$second_term->name], check_plain($second_term->name), 'Autocomplete returned the second matching term');
+
+ // Try to autocomplete a term name that matches first term.
+ // We should only get the first term in a json encoded string.
+ $input = '10/16';
+ $url = 'taxonomy/autocomplete/taxonomy_';
+ $url .= $this->vocabulary->machine_name . '/' . $input;
+ $this->drupalGet($url);
+ $target = array($first_term->name => check_plain($first_term->name));
+ $this->assertRaw(drupal_json_encode($target), 'Autocomplete returns only the expected matching term.');
+
+ // Try to autocomplete a term name with both a comma and a slash.
+ $input = '"term with, comma and / a';
+ $url = 'taxonomy/autocomplete/taxonomy_';
+ $url .= $this->vocabulary->machine_name . '/' . $input;
+ $this->drupalGet($url);
+ $n = $third_term->name;
+ // Term names containing commas or quotes must be wrapped in quotes.
+ if (strpos($third_term->name, ',') !== FALSE || strpos($third_term->name, '"') !== FALSE) {
+ $n = '"' . str_replace('"', '""', $third_term->name) . '"';
+ }
+ $target = array($n => check_plain($third_term->name));
+ $this->assertRaw(drupal_json_encode($target), 'Autocomplete returns a term containing a comma and a slash.');
+ }
+
+ /**
* Save, edit and delete a term using the user interface.
*/
function testTermInterface() {
@@ -950,7 +1017,7 @@ class TaxonomyRSSTestCase extends TaxonomyWebTestCase {
}
function setUp() {
- parent::setUp('taxonomy');
+ parent::setUp(array('node', 'field_ui'));
$this->admin_user = $this->drupalCreateUser(array('administer taxonomy', 'bypass node access', 'administer content types'));
$this->drupalLogin($this->admin_user);
$this->vocabulary = $this->createVocabulary();
@@ -1011,7 +1078,7 @@ class TaxonomyRSSTestCase extends TaxonomyWebTestCase {
// Post an article.
$edit = array();
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$edit["title"] = $this->randomName();
$edit[$this->instance['field_name'] . '[' . $langcode .'][]'] = $term1->tid;
$this->drupalPost('node/add/article', $edit, t('Save'));
@@ -1043,7 +1110,7 @@ class TaxonomyTermIndexTestCase extends TaxonomyWebTestCase {
}
function setUp() {
- parent::setUp('taxonomy');
+ parent::setUp();
// Create an administrative user.
$this->admin_user = $this->drupalCreateUser(array('administer taxonomy', 'bypass node access'));
@@ -1123,7 +1190,7 @@ class TaxonomyTermIndexTestCase extends TaxonomyWebTestCase {
// Post an article.
$edit = array();
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$edit["title"] = $this->randomName();
$edit["body[$langcode][0][value]"] = $this->randomName();
$edit["{$this->field_name_1}[$langcode][]"] = $term_1->tid;
@@ -1326,7 +1393,7 @@ class TaxonomyHooksTestCase extends TaxonomyWebTestCase {
}
function setUp() {
- parent::setUp('taxonomy', 'taxonomy_test');
+ parent::setUp(array('taxonomy_test'));
$taxonomy_admin = $this->drupalCreateUser(array('administer taxonomy'));
$this->drupalLogin($taxonomy_admin);
}
@@ -1422,7 +1489,7 @@ class TaxonomyTermFieldTestCase extends TaxonomyWebTestCase {
*/
function testTaxonomyTermFieldValidation() {
// Test valid and invalid values with field_attach_validate().
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$entity = field_test_create_stub_entity();
$term = $this->createTerm($this->vocabulary);
$entity->{$this->field_name}[$langcode][0]['tid'] = $term->tid;
@@ -1454,7 +1521,7 @@ class TaxonomyTermFieldTestCase extends TaxonomyWebTestCase {
$term = $this->createTerm($this->vocabulary);
// Display creation form.
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$this->drupalGet('test-entity/add/test-bundle');
$this->assertFieldByName("{$this->field_name}[$langcode]", '', t('Widget is displayed'));
@@ -1585,7 +1652,7 @@ class TaxonomyTermFieldMultipleVocabularyTestCase extends TaxonomyWebTestCase {
$term2 = $this->createTerm($this->vocabulary2);
// Submit an entity with both terms.
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$this->drupalGet('test-entity/add/test-bundle');
$this->assertFieldByName("{$this->field_name}[$langcode][]", '', 'Widget is displayed');
$edit = array(
@@ -1654,7 +1721,7 @@ class TaxonomyTokenReplaceTestCase extends TaxonomyWebTestCase {
$this->admin_user = $this->drupalCreateUser(array('administer taxonomy', 'bypass node access'));
$this->drupalLogin($this->admin_user);
$this->vocabulary = $this->createVocabulary();
- $this->langcode = LANGUAGE_NONE;
+ $this->langcode = LANGUAGE_NOT_SPECIFIED;
$field = array(
'field_name' => 'taxonomy_' . $this->vocabulary->machine_name,
diff --git a/core/modules/toolbar/toolbar.js b/core/modules/toolbar/toolbar.js
index 5b61634..d50f205 100644
--- a/core/modules/toolbar/toolbar.js
+++ b/core/modules/toolbar/toolbar.js
@@ -94,11 +94,16 @@ Drupal.toolbar.toggle = function() {
};
Drupal.toolbar.height = function() {
- var height = $('#toolbar').outerHeight();
- // In IE, Shadow filter adds some extra height, so we need to remove it from
- // the returned height.
- if ($('#toolbar').css('filter').match(/DXImageTransform\.Microsoft\.Shadow/)) {
- height -= $('#toolbar').get(0).filters.item("DXImageTransform.Microsoft.Shadow").strength;
+ var $toolbar = $('#toolbar');
+ var height = $toolbar.outerHeight();
+ // In modern browsers (including IE9), when box-shadow is defined, use the
+ // normal height.
+ var cssBoxShadowValue = $toolbar.css('box-shadow');
+ var boxShadow = (typeof cssBoxShadowValue !== 'undefined' && cssBoxShadowValue !== 'none');
+ // In IE8 and below, we use the shadow filter to apply box-shadow styles to
+ // the toolbar. It adds some extra height that we need to remove.
+ if (!boxShadow && /DXImageTransform\.Microsoft\.Shadow/.test($toolbar.css('filter'))) {
+ height -= $toolbar[0].filters.item("DXImageTransform.Microsoft.Shadow").strength;
}
return height;
};
diff --git a/core/modules/tracker/tracker.test b/core/modules/tracker/tracker.test
index d429210..c6d4a29 100644
--- a/core/modules/tracker/tracker.test
+++ b/core/modules/tracker/tracker.test
@@ -35,6 +35,8 @@ class TrackerTest extends DrupalWebTestCase {
function setUp() {
parent::setUp('comment', 'tracker');
+ $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
+
$permissions = array('access comments', 'create page content', 'post comments', 'skip comment approval');
$this->user = $this->drupalCreateUser($permissions);
$this->other_user = $this->drupalCreateUser($permissions);
@@ -97,7 +99,7 @@ class TrackerTest extends DrupalWebTestCase {
));
$comment = array(
'subject' => $this->randomName(),
- 'comment_body[' . LANGUAGE_NONE . '][0][value]' => $this->randomName(20),
+ 'comment_body[' . LANGUAGE_NOT_SPECIFIED . '][0][value]' => $this->randomName(20),
);
$this->drupalPost('comment/reply/' . $other_published_my_comment->nid, $comment, t('Save'));
@@ -108,7 +110,7 @@ class TrackerTest extends DrupalWebTestCase {
$this->assertText($other_published_my_comment->title, t("Nodes that the user has commented on appear in the user's tracker listing."));
// Verify that unpublished comments are removed from the tracker.
- $admin_user = $this->drupalCreateUser(array('administer comments', 'access user profiles'));
+ $admin_user = $this->drupalCreateUser(array('post comments', 'administer comments', 'access user profiles'));
$this->drupalLogin($admin_user);
$this->drupalPost('comment/1/edit', array('status' => COMMENT_NOT_PUBLISHED), t('Save'));
$this->drupalGet('user/' . $this->user->uid . '/track');
@@ -151,13 +153,13 @@ class TrackerTest extends DrupalWebTestCase {
$node = $this->drupalCreateNode(array(
'comment' => 2,
- 'title' => array(LANGUAGE_NONE => array(array('value' => $this->randomName(8)))),
+ 'title' => array(LANGUAGE_NOT_SPECIFIED => array(array('value' => $this->randomName(8)))),
));
// Add a comment to the page.
$comment = array(
'subject' => $this->randomName(),
- 'comment_body[' . LANGUAGE_NONE . '][0][value]' => $this->randomName(20),
+ 'comment_body[' . LANGUAGE_NOT_SPECIFIED . '][0][value]' => $this->randomName(20),
);
// The new comment is automatically viewed by the current user.
$this->drupalPost('comment/reply/' . $node->nid, $comment, t('Save'));
@@ -170,7 +172,7 @@ class TrackerTest extends DrupalWebTestCase {
// Add another comment as other_user.
$comment = array(
'subject' => $this->randomName(),
- 'comment_body[' . LANGUAGE_NONE . '][0][value]' => $this->randomName(20),
+ 'comment_body[' . LANGUAGE_NOT_SPECIFIED . '][0][value]' => $this->randomName(20),
);
// If the comment is posted in the same second as the last one then Drupal
// can't tell the difference, so we wait one second here.
@@ -203,7 +205,7 @@ class TrackerTest extends DrupalWebTestCase {
$this->drupalLogin($this->other_user);
$comment = array(
'subject' => $this->randomName(),
- 'comment_body[' . LANGUAGE_NONE . '][0][value]' => $this->randomName(20),
+ 'comment_body[' . LANGUAGE_NOT_SPECIFIED . '][0][value]' => $this->randomName(20),
);
$this->drupalPost('comment/reply/' . $nodes[3]->nid, $comment, t('Save'));
diff --git a/core/modules/translation/translation.module b/core/modules/translation/translation.module
index bb2d7e3..4e24408 100644
--- a/core/modules/translation/translation.module
+++ b/core/modules/translation/translation.module
@@ -2,21 +2,21 @@
/**
* @file
- * Manages content translations.
+ * Manages content translations.
*
- * Translations are managed in sets of posts, which represent the same
- * information in different languages. Only content types for which the
- * administrator explicitly enabled translations could have translations
- * associated. Translations are managed in sets with exactly one source
- * post per set. The source post is used to translate to different
- * languages, so if the source post is significantly updated, the
- * editor can decide to mark all translations outdated.
+ * Translations are managed in sets of posts, which represent the same
+ * information in different languages. Only content types for which the
+ * administrator has explicitly enabled translations could have translations
+ * associated. Translations are managed in sets with exactly one source post
+ * per set. The source post is used to translate to different languages, so if
+ * the source post is significantly updated, the editor can decide to mark all
+ * translations outdated.
*
- * The node table stores the values used by this module:
- * - 'tnid' is the translation set id, which equals the node id
- * of the source post.
- * - 'translate' is a flag, either indicating that the translation
- * is up to date (0) or needs to be updated (1).
+ * The node table stores the values used by this module:
+ * - tnid: Integer for the translation set ID, which equals the node ID of the
+ * source post.
+ * - translate: Integer flag, either indicating that the translation is up to
+ * date (0) or needs to be updated (1).
*/
/**
@@ -70,14 +70,21 @@ function translation_menu() {
}
/**
- * Menu access callback.
+ * Access callback: Checks that the user has permission to 'translate content'.
*
- * Only display translation tab for node types, which have translation enabled
- * and where the current node is not language neutral (which should span
- * all languages).
+ * Only displays the translation tab for nodes that are not language-neutral
+ * of types that have translation enabled.
+ *
+ * @param $node
+ * A node object.
+ *
+ * @return
+ * TRUE if the translation tab should be displayed, FALSE otherwise.
+ *
+ * @see translation_menu()
*/
function _translation_tab_access($node) {
- if ($node->langcode != LANGUAGE_NONE && translation_supported_type($node->type) && node_access('view', $node)) {
+ if ($node->langcode != LANGUAGE_NOT_SPECIFIED && translation_supported_type($node->type) && node_access('view', $node)) {
return user_access('translate content');
}
return FALSE;
@@ -107,7 +114,7 @@ function translation_permission() {
}
/**
- * Implements hook_form_FORM_ID_alter().
+ * Implements hook_form_FORM_ID_alter() for node_type_form().
*/
function translation_form_node_type_form_alter(&$form, &$form_state) {
// Add translation option to content type form.
@@ -118,10 +125,12 @@ function translation_form_node_type_form_alter(&$form, &$form_state) {
}
/**
- * Implements hook_form_BASE_FORM_ID_alter().
+ * Implements hook_form_BASE_FORM_ID_alter() for node_form().
*
- * This function alters language fields on node edit forms when a translation is
- * about to be created.
+ * Alters language fields on node edit forms when a translation is about to be
+ * created.
+ *
+ * @see node_form()
*/
function translation_form_node_form_alter(&$form, &$form_state) {
if (translation_supported_type($form['#node']->type)) {
@@ -140,7 +149,7 @@ function translation_form_node_form_alter(&$form, &$form_state) {
// might need to distinguish between enabled and disabled languages, hence
// we divide them in two option groups.
if ($translator_widget) {
- $options = array($groups[1] => array(LANGUAGE_NONE => t('- None -')));
+ $options = array($groups[1] => array(LANGUAGE_NOT_SPECIFIED => t('- None -')));
foreach (array(1, 0) as $status) {
$group = $groups[$status];
foreach ($grouped_languages[$status] as $langcode => $language) {
@@ -158,7 +167,7 @@ function translation_form_node_form_alter(&$form, &$form_state) {
// Disable languages for existing translations, so it is not possible to switch this
// node to some language which is already in the translation set. Also remove the
// language neutral option.
- unset($form['langcode']['#options'][LANGUAGE_NONE]);
+ unset($form['langcode']['#options'][LANGUAGE_NOT_SPECIFIED]);
foreach (translation_node_get_translations($node->tnid) as $langcode => $translation) {
if ($translation->nid != $node->nid) {
if ($translator_widget) {
@@ -206,9 +215,9 @@ function translation_form_node_form_alter(&$form, &$form_state) {
/**
* Implements hook_node_view().
*
- * Display translation links with language names, if this node is part of
- * a translation set. If no language provider is enabled "fall back" to the
- * simple links built through the result of translation_node_get_translations().
+ * Displays translation links with language names if this node is part of a
+ * translation set. If no language provider is enabled, "fall back" to simple
+ * links built through the result of translation_node_get_translations().
*/
function translation_node_view($node, $view_mode) {
// If the site has no translations or is not multilingual we have no content
@@ -378,7 +387,7 @@ function translation_node_update($node) {
/**
* Implements hook_node_validate().
*
- * Ensure that duplicate translations can not be created for the same source.
+ * Ensures that duplicate translations can't be created for the same source.
*/
function translation_node_validate($node, $form) {
// Only act on translatable nodes with a tnid or translation_source.
@@ -402,8 +411,10 @@ function translation_node_predelete($node) {
}
/**
- * Remove a node from its translation set (if any)
- * and update the set accordingly.
+ * Removes a node from its translation set and updates accordingly.
+ *
+ * @param $node
+ * A node object.
*/
function translation_remove_from_set($node) {
if (isset($node->tnid)) {
@@ -437,17 +448,18 @@ function translation_remove_from_set($node) {
}
/**
- * Get all nodes in a translation set, represented by $tnid.
+ * Gets all nodes in a given translation set.
*
* @param $tnid
- * The translation source nid of the translation set, the identifier
- * of the node used to derive all translations in the set.
+ * The translation source nid of the translation set, the identifier of the
+ * node used to derive all translations in the set.
+ *
* @return
- * Array of partial node objects (nid, title, langcode) representing
- * all nodes in the translation set, in effect all translations
- * of node $tnid, including node $tnid itself. Because these are
- * partial nodes, you need to node_load() the full node, if you
- * need more properties. The array is indexed by language code.
+ * Array of partial node objects (nid, title, langcode) representing all
+ * nodes in the translation set, in effect all translations of node $tnid,
+ * including node $tnid itself. Because these are partial nodes, you need to
+ * node_load() the full node, if you need more properties. The array is
+ * indexed by language code.
*/
function translation_node_get_translations($tnid) {
if (is_numeric($tnid) && $tnid) {
@@ -473,21 +485,21 @@ function translation_node_get_translations($tnid) {
* Returns whether the given content type has support for translations.
*
* @return
- * Boolean value.
+ * TRUE if translation is supported, and FALSE if not.
*/
function translation_supported_type($type) {
return variable_get('node_type_language_' . $type, 0) == TRANSLATION_ENABLED;
}
/**
- * Return paths of all translations of a node, based on
- * its Drupal path.
+ * Returns the paths of all translations of a node, based on its Drupal path.
*
* @param $path
* A Drupal path, for example node/432.
+ *
* @return
- * An array of paths of translations of the node accessible
- * to the current user keyed with language codes.
+ * An array of paths of translations of the node accessible to the current
+ * user, keyed with language codes.
*/
function translation_path_get_translations($path) {
$paths = array();
@@ -516,7 +528,7 @@ function translation_language_switch_links_alter(array &$links, $type, $path) {
// have translations it might be a language neutral node, in which case we
// must leave the language switch links unaltered. This is true also for
// nodes not having translation support enabled.
- if (empty($node) || $node->langcode == LANGUAGE_NONE || !translation_supported_type($node->type)) {
+ if (empty($node) || $node->langcode == LANGUAGE_NOT_SPECIFIED || !translation_supported_type($node->type)) {
return;
}
$translations = array($node->langcode => $node);
diff --git a/core/modules/translation/translation.pages.inc b/core/modules/translation/translation.pages.inc
index fd69d34..66dfc42 100644
--- a/core/modules/translation/translation.pages.inc
+++ b/core/modules/translation/translation.pages.inc
@@ -2,14 +2,19 @@
/**
* @file
- * User page callbacks for the translation module.
+ * User page callbacks for the Translation module.
*/
/**
- * Overview page for a node's translations.
+ * Page callback: Displays a list of a node's translations.
*
* @param $node
- * Node object.
+ * A node object.
+ *
+ * @return
+ * A render array for a page containing a list of content.
+ *
+ * @see translation_menu()
*/
function translation_node_overview($node) {
include_once DRUPAL_ROOT . '/core/includes/language.inc';
diff --git a/core/modules/translation/translation.test b/core/modules/translation/translation.test
index 2a77c03..e2b8358 100644
--- a/core/modules/translation/translation.test
+++ b/core/modules/translation/translation.test
@@ -2,10 +2,15 @@
/**
* @file
- * Tests for translation.module
+ * Tests for the Translation module.
*/
+/**
+ * Functional tests for the Translation module.
+ */
class TranslationTestCase extends DrupalWebTestCase {
+ protected $profile = 'standard';
+
protected $book;
public static function getInfo() {
@@ -54,8 +59,7 @@ class TranslationTestCase extends DrupalWebTestCase {
}
/**
- * Create a basic page with translation, modify the basic page outdating
- * translation, and update translation.
+ * Creates, modifies, and updates a basic page with a translation.
*/
function testContentTranslation() {
// Create Basic page in English.
@@ -95,7 +99,7 @@ class TranslationTestCase extends DrupalWebTestCase {
// Attempt a resubmission of the form - this emulates using the back button
// to return to the page then resubmitting the form without a refresh.
$edit = array();
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$edit["title"] = $this->randomName();
$edit["body[$langcode][0][value]"] = $this->randomName();
$this->drupalPost('node/add/page', $edit, t('Save'), array('query' => array('translation' => $node->nid, 'language' => 'es')));
@@ -104,7 +108,7 @@ class TranslationTestCase extends DrupalWebTestCase {
// Update original and mark translation as outdated.
$node_body = $this->randomName();
- $node->body[LANGUAGE_NONE][0]['value'] = $node_body;
+ $node->body[LANGUAGE_NOT_SPECIFIED][0]['value'] = $node_body;
$edit = array();
$edit["body[$langcode][0][value]"] = $node_body;
$edit['translation[retranslate]'] = TRUE;
@@ -127,14 +131,14 @@ class TranslationTestCase extends DrupalWebTestCase {
$this->drupalGet('node/add/page');
$this->assertFieldByXPath('//select[@name="langcode"]//option', 'it', t('Italian (disabled) is available in language selection.'));
$translation_it = $this->createTranslation($node, $this->randomName(), $this->randomName(), 'it');
- $this->assertRaw($translation_it->body[LANGUAGE_NONE][0]['value'], t('Content created in Italian (disabled).'));
+ $this->assertRaw($translation_it->body[LANGUAGE_NOT_SPECIFIED][0]['value'], t('Content created in Italian (disabled).'));
// Confirm that language neutral is an option for translators when there are
// disabled languages.
$this->drupalGet('node/add/page');
- $this->assertFieldByXPath('//select[@name="langcode"]//option', LANGUAGE_NONE, t('Language neutral is available in language selection with disabled languages.'));
- $node2 = $this->createPage($this->randomName(), $this->randomName(), LANGUAGE_NONE);
- $this->assertRaw($node2->body[LANGUAGE_NONE][0]['value'], t('Language neutral content created with disabled languages available.'));
+ $this->assertFieldByXPath('//select[@name="langcode"]//option', LANGUAGE_NOT_SPECIFIED, t('Language neutral is available in language selection with disabled languages.'));
+ $node2 = $this->createPage($this->randomName(), $this->randomName(), LANGUAGE_NOT_SPECIFIED);
+ $this->assertRaw($node2->body[LANGUAGE_NOT_SPECIFIED][0]['value'], t('Language neutral content created with disabled languages available.'));
// Leave just one language enabled and check that the translation overview
// page is still accessible.
@@ -147,7 +151,7 @@ class TranslationTestCase extends DrupalWebTestCase {
}
/**
- * Check that language switch links behave properly.
+ * Checks that the language switch links behave properly.
*/
function testLanguageSwitchLinks() {
// Create a Basic page in English and its translations in Spanish and
@@ -188,7 +192,7 @@ class TranslationTestCase extends DrupalWebTestCase {
}
/**
- * Test that the language switcher block alterations work as intended.
+ * Tests that the language switcher block alterations work as intended.
*/
function testLanguageSwitcherBlockIntegration() {
// Enable Italian to have three items in the language switcher block.
@@ -219,7 +223,7 @@ class TranslationTestCase extends DrupalWebTestCase {
// Create a language neutral node and check that the language switcher is
// left untouched.
- $node2 = $this->createPage($this->randomName(), $this->randomName(), LANGUAGE_NONE);
+ $node2 = $this->createPage($this->randomName(), $this->randomName(), LANGUAGE_NOT_SPECIFIED);
$node2_en = (object) array('nid' => $node2->nid, 'langcode' => 'en');
$node2_es = (object) array('nid' => $node2->nid, 'langcode' => 'es');
$node2_it = (object) array('nid' => $node2->nid, 'langcode' => 'it');
@@ -251,7 +255,7 @@ class TranslationTestCase extends DrupalWebTestCase {
}
/**
- * Reset static caches to make the test code match the client site behavior.
+ * Resets static caches to make the test code match the client-side behavior.
*/
function resetCaches() {
drupal_static_reset('language_list');
@@ -260,18 +264,23 @@ class TranslationTestCase extends DrupalWebTestCase {
}
/**
- * Return an empty node data structure.
+ * Returns an empty node data structure.
+ *
+ * @param $langcode
+ * The language code.
+ *
+ * @return
+ * An empty node data structure.
*/
function emptyNode($langcode) {
return (object) array('nid' => NULL, 'langcode' => $langcode);
}
/**
- * Install a the specified language if it has not been already. Otherwise make sure that
- * the language is enabled.
+ * Installs the specified language, or enables it if it is already installed.
*
* @param $language_code
- * The language code the check.
+ * The language code to check.
*/
function addLanguage($language_code) {
// Check to make sure that language has not already been installed.
@@ -305,18 +314,21 @@ class TranslationTestCase extends DrupalWebTestCase {
}
/**
- * Create a "Basic page" in the specified language.
+ * Creates a "Basic page" in the specified language.
*
* @param $title
- * Title of basic page in specified language.
+ * The title of a basic page in the specified language.
* @param $body
- * Body of basic page in specified language.
+ * The body of a basic page in the specified language.
* @param $langcode
* (optional) Language code.
+ *
+ * @return
+ * A node object.
*/
function createPage($title, $body, $langcode = NULL) {
$edit = array();
- $field_langcode = LANGUAGE_NONE;
+ $field_langcode = LANGUAGE_NOT_SPECIFIED;
$edit["title"] = $title;
$edit["body[$field_langcode][0][value]"] = $body;
if (!empty($langcode)) {
@@ -333,25 +345,27 @@ class TranslationTestCase extends DrupalWebTestCase {
}
/**
- * Create a translation for the specified basic page in the specified
- * language.
+ * Creates a translation for a basic page in the specified language.
*
* @param $node
- * The basic page to create translation for.
+ * The basic page to create the translation for.
* @param $title
- * Title of basic page in specified language.
+ * The title of a basic page in the specified language.
* @param $body
- * Body of basic page in specified language.
+ * The body of a basic page in the specified language.
* @param $langcode
- * Language code.
+ * (optional) Language code.
+ *
+ * @return
+ * Translation object.
*/
function createTranslation($node, $title, $body, $langcode) {
$this->drupalGet('node/add/page', array('query' => array('translation' => $node->nid, 'target' => $langcode)));
- $field_langcode = LANGUAGE_NONE;
+ $field_langcode = LANGUAGE_NOT_SPECIFIED;
$body_key = "body[$field_langcode][0][value]";
$this->assertFieldByXPath('//input[@id="edit-title"]', $node->title, "Original title value correctly populated.");
- $this->assertFieldByXPath("//textarea[@name='$body_key']", $node->body[LANGUAGE_NONE][0]['value'], "Original body value correctly populated.");
+ $this->assertFieldByXPath("//textarea[@name='$body_key']", $node->body[LANGUAGE_NOT_SPECIFIED][0]['value'], "Original body value correctly populated.");
$edit = array();
$edit["title"] = $title;
@@ -368,10 +382,10 @@ class TranslationTestCase extends DrupalWebTestCase {
}
/**
- * Assert that an element identified by the given XPath has the given content.
+ * Asserts an element identified by the given XPath has the given content.
*
* @param $xpath
- * XPath used to find the element.
+ * The XPath used to find the element.
* @param array $arguments
* An array of arguments with keys in the form ':name' matching the
* placeholders in the query. The values may be either strings or numeric
@@ -379,7 +393,7 @@ class TranslationTestCase extends DrupalWebTestCase {
* @param $value
* The text content of the matched element to assert.
* @param $message
- * Message to display.
+ * The message to display.
* @param $group
* The group this message belongs to.
*
@@ -392,7 +406,7 @@ class TranslationTestCase extends DrupalWebTestCase {
}
/**
- * Check that the specified language switch links are found/not found.
+ * Tests whether the specified language switch links are found.
*
* @param $node
* The node to display.
@@ -404,7 +418,7 @@ class TranslationTestCase extends DrupalWebTestCase {
* The page areas to be checked.
*
* @return
- * TRUE if the language switch links are found/not found.
+ * TRUE if the language switch links are found, FALSE if not.
*/
function assertLanguageSwitchLinks($node, $translation, $find = TRUE, $types = NULL) {
if (empty($types)) {
@@ -446,7 +460,19 @@ class TranslationTestCase extends DrupalWebTestCase {
}
/**
- * Search for elements matching the given xpath and value.
+ * Searches for elements matching the given xpath and value.
+ *
+ * @param $xpath
+ * The XPath used to find the element.
+ * @param array $arguments
+ * An array of arguments with keys in the form ':name' matching the
+ * placeholders in the query. The values may be either strings or numeric
+ * values.
+ * @param $value
+ * The text content of the matched element to assert.
+ *
+ * @return
+ * TRUE if found, otherwise FALSE.
*/
function findContentByXPath($xpath, array $arguments = array(), $value = NULL) {
$elements = $this->xpath($xpath, $arguments);
diff --git a/core/modules/update/update.authorize.inc b/core/modules/update/update.authorize.inc
index 35dde0e..48dfd35 100644
--- a/core/modules/update/update.authorize.inc
+++ b/core/modules/update/update.authorize.inc
@@ -9,6 +9,8 @@
* the rest of the update module code.
*/
+use Drupal\Core\Updater\UpdaterException;
+
/**
* Callback invoked by authorize.php to update existing projects.
*
@@ -19,7 +21,8 @@
* A nested array of projects to install into the live webroot, keyed by
* project name. Each subarray contains the following keys:
* - 'project': The canonical project short name.
- * - 'updater_name': The name of the Updater class to use for this project.
+ * - 'updater_name': The name of the Drupal\Core\Updater\Updater class to use
+ * for this project.
* - 'local_url': The locally installed location of new code to update with.
*/
function update_authorize_run_update($filetransfer, $projects) {
@@ -58,7 +61,8 @@ function update_authorize_run_update($filetransfer, $projects) {
* @param string $project
* The canonical project short name (e.g. {system}.name).
* @param string $updater_name
- * The name of the Updater class to use for installing this project.
+ * The name of the Drupal\Core\Updater\Updater class to use for installing
+ * this project.
* @param string $local_url
* The URL to the locally installed temp directory where the project has
* already been downloaded and extracted into.
@@ -95,7 +99,8 @@ function update_authorize_run_install($filetransfer, $project, $updater_name, $l
* @param string $project
* The canonical short name of the project being installed.
* @param string $updater_name
- * The name of the Updater class to use for installing this project.
+ * The name of the Drupal\Core\Updater\Updater class to use for installing
+ * this project.
* @param string $local_url
* The URL to the locally installed temp directory where the project has
* already been downloaded and extracted into.
diff --git a/core/modules/update/update.fetch.inc b/core/modules/update/update.fetch.inc
index 7ac0dbe..ec3bfbc 100644
--- a/core/modules/update/update.fetch.inc
+++ b/core/modules/update/update.fetch.inc
@@ -28,7 +28,7 @@ function update_manual_status() {
* Process a step in the batch for fetching available update data.
*/
function update_fetch_data_batch(&$context) {
- $queue = DrupalQueue::get('update_fetch_tasks');
+ $queue = queue('update_fetch_tasks');
if (empty($context['sandbox']['max'])) {
$context['finished'] = 0;
$context['sandbox']['max'] = $queue->numberOfItems();
@@ -99,7 +99,7 @@ function update_fetch_data_finished($success, $results) {
* Attempt to drain the queue of tasks for release history data to fetch.
*/
function _update_fetch_data() {
- $queue = DrupalQueue::get('update_fetch_tasks');
+ $queue = queue('update_fetch_tasks');
$end = time() + variable_get('update_max_fetch_time', UPDATE_MAX_FETCH_TIME);
while (time() < $end && ($item = $queue->claimItem())) {
_update_process_fetch_task($item->data);
@@ -235,7 +235,7 @@ function _update_create_fetch_task($project) {
}
$cid = 'fetch_task::' . $project['name'];
if (empty($fetch_tasks[$cid])) {
- $queue = DrupalQueue::get('update_fetch_tasks');
+ $queue = queue('update_fetch_tasks');
$queue->createItem($project);
db_insert('cache_update')
->fields(array(
diff --git a/core/modules/update/update.install b/core/modules/update/update.install
index f0d5499..9ff39d1 100644
--- a/core/modules/update/update.install
+++ b/core/modules/update/update.install
@@ -70,7 +70,7 @@ function update_schema() {
* Implements hook_install().
*/
function update_install() {
- $queue = DrupalQueue::get('update_fetch_tasks', TRUE);
+ $queue = queue('update_fetch_tasks', TRUE);
$queue->createQueue();
}
@@ -91,7 +91,7 @@ function update_uninstall() {
foreach ($variables as $variable) {
variable_del($variable);
}
- $queue = DrupalQueue::get('update_fetch_tasks');
+ $queue = queue('update_fetch_tasks');
$queue->deleteQueue();
}
diff --git a/core/modules/update/update.manager.inc b/core/modules/update/update.manager.inc
index d9fd86f..82b48f3 100644
--- a/core/modules/update/update.manager.inc
+++ b/core/modules/update/update.manager.inc
@@ -35,6 +35,8 @@
* into the live web root.
*/
+use Drupal\Core\Updater\Updater;
+
/**
* @defgroup update_manager_update Update manager: update
* @{
@@ -393,9 +395,10 @@ function update_manager_update_ready_form($form, &$form_state) {
*
* If the site administrator requested that the site is put offline during the
* update, do so now. Otherwise, pull information about all the required
- * updates out of the SESSION, figure out what Updater class is needed for
- * each one, generate an array of update operations to perform, and hand it
- * all off to system_authorized_init(), then redirect to authorize.php.
+ * updates out of the SESSION, figure out what Drupal\Core\Updater\Updater class
+ * is needed for each one, generate an array of update operations to perform,
+ * and hand it all off to system_authorized_init(), then redirect to
+ * authorize.php.
*
* @see update_authorize_run_update()
* @see system_authorized_init()
@@ -492,7 +495,7 @@ function update_manager_install_form($form, &$form_state, $context) {
);
$form['project_url'] = array(
- '#type' => 'textfield',
+ '#type' => 'url',
'#title' => t('Install from a URL'),
'#description' => t('For example: %url', array('%url' => 'http://ftp.drupal.org/files/projects/name.tar.gz')),
);
@@ -592,12 +595,6 @@ function update_manager_install_form_validate($form, &$form_state) {
if (!($form_state['values']['project_url'] XOR !empty($_FILES['files']['name']['project_upload']))) {
form_set_error('project_url', t('You must either provide a URL or upload an archive file to install.'));
}
-
- if ($form_state['values']['project_url']) {
- if (!valid_url($form_state['values']['project_url'], TRUE)) {
- form_set_error('project_url', t('The provided URL is invalid.'));
- }
- }
}
/**
@@ -606,10 +603,10 @@ function update_manager_install_form_validate($form, &$form_state) {
* Either downloads the file specified in the URL to a temporary cache, or
* uploads the file attached to the form, then attempts to extract the archive
* into a temporary location and verify it. Instantiate the appropriate
- * Updater class for this project and make sure it is not already installed in
- * the live webroot. If everything is successful, setup an operation to run
- * via authorize.php which will copy the extracted files from the temporary
- * location into the live site.
+ * Drupal\Core\Updater\Updater class for this project and make sure it is not
+ * already installed in the live webroot. If everything is successful, setup an
+ * operation to run via authorize.php which will copy the extracted files from
+ * the temporary location into the live site.
*
* @see update_authorize_run_install()
* @see system_authorized_init()
diff --git a/core/modules/user/user.install b/core/modules/user/user.install
index f7175c3..9b70e09 100644
--- a/core/modules/user/user.install
+++ b/core/modules/user/user.install
@@ -137,6 +137,13 @@ function user_schema() {
'default' => '',
'description' => 'Unique user name.',
),
+ 'langcode' => array(
+ 'type' => 'varchar',
+ 'length' => 12,
+ 'not null' => TRUE,
+ 'default' => '',
+ 'description' => "The {language}.langcode of the user's profile.",
+ ),
'pass' => array(
'type' => 'varchar',
'length' => 128,
@@ -202,12 +209,12 @@ function user_schema() {
'not null' => FALSE,
'description' => "User's time zone.",
),
- 'language' => array(
+ 'preferred_langcode' => array(
'type' => 'varchar',
'length' => 12,
'not null' => TRUE,
'default' => '',
- 'description' => "User's default language.",
+ 'description' => 'The {language}.langcode that the user prefers for receiving emails and viewing the site.',
),
'picture' => array(
'type' => 'int',
@@ -354,5 +361,40 @@ function user_update_8000() {
}
/**
+ * Splits {users}.language field to langcode and preferred_langcode.
+ *
+ * @see http://drupal.org/node/1454538
+ */
+function user_update_8001() {
+ // The former language field is the language preference of the user. Rename
+ // this to preferred_langcode in order to distinguish it from the langcode
+ // field common to all entity types, used for identifying the language of the
+ // entity itself.
+ $preferred_langcode_field = array(
+ 'type' => 'varchar',
+ 'length' => 12,
+ 'not null' => TRUE,
+ 'default' => '',
+ 'description' => 'The {language}.langcode that the user prefers for receiving emails and viewing the site.',
+ );
+ db_change_field('users', 'language', 'preferred_langcode', $preferred_langcode_field);
+
+ // Add the langcode field.
+ $langcode_field = array(
+ 'type' => 'varchar',
+ 'length' => 12,
+ 'not null' => TRUE,
+ 'default' => '',
+ 'description' => "The {language}.langcode of the user's profile.",
+ );
+ db_add_field('users', 'langcode', $langcode_field);
+
+ // Since distinguishing the language of the user entity from the user's
+ // preferred language is a new feature in Drupal 8, assume that for updated
+ // sites, existing user entities are in the user's preferred language.
+ db_update('users')->expression('langcode', 'preferred_langcode')->execute();
+}
+
+/**
* @} End of "addtogroup updates-7.x-to-8.x"
*/
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 3ac4cd6..00c91ac 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -395,9 +395,6 @@ function user_save($account, $edit = array()) {
// Avoid overwriting an existing password with a blank password.
unset($edit['pass']);
}
- if (isset($edit['mail'])) {
- $edit['mail'] = trim($edit['mail']);
- }
// Load the stored entity, if any.
if (!empty($account->uid) && !isset($account->original)) {
@@ -425,6 +422,10 @@ function user_save($account, $edit = array()) {
foreach ($edit as $key => $value) {
$account->$key = $value;
}
+ // Default the user entity language to the user's preferred language.
+ if (!isset($account->langcode) && isset($account->preferred_langcode)) {
+ $account->langcode = $account->preferred_langcode;
+ }
field_attach_presave('user', $account);
module_invoke_all('entity_presave', $account, 'user');
@@ -609,28 +610,6 @@ function user_validate_name($name) {
}
/**
- * Validates a user's email address.
- *
- * Checks that a user's email address exists and follows all standard
- * validation rules. Returns error messages when the address is invalid.
- *
- * @param $mail
- * A user's email address.
- *
- * @return
- * If the address is invalid, a human-readable error message is returned.
- * If the address is valid, nothing is returned.
- */
-function user_validate_mail($mail) {
- if (!$mail) {
- return t('You must enter an e-mail address.');
- }
- if (!valid_email_address($mail)) {
- return t('The e-mail address %mail is not valid.', array('%mail' => $mail));
- }
-}
-
-/**
* Validates an image uploaded by a user.
*
* @see user_account_form()
@@ -965,9 +944,8 @@ function user_account_form(&$form, &$form_state) {
);
$form['account']['mail'] = array(
- '#type' => 'textfield',
+ '#type' => 'email',
'#title' => t('E-mail address'),
- '#maxlength' => EMAIL_MAX_LENGTH,
'#description' => t('A valid e-mail address. All e-mails from the system will be sent to this address. The e-mail address is not made public and will only be used if you wish to receive a new password or wish to receive certain news or notifications by e-mail.'),
'#required' => TRUE,
'#default_value' => (!$register ? $account->mail : ''),
@@ -1149,22 +1127,15 @@ function user_account_form_validate($form, &$form_state) {
}
}
- // Trim whitespace from mail, to prevent confusing 'e-mail not valid'
- // warnings often caused by cutting and pasting.
- $mail = trim($form_state['values']['mail']);
- form_set_value($form['account']['mail'], $mail, $form_state);
+ $mail = $form_state['values']['mail'];
- // Validate the e-mail address, and check if it is taken by an existing user.
- if ($error = user_validate_mail($form_state['values']['mail'])) {
- form_set_error('mail', $error);
- }
- elseif ((bool) db_select('users')->fields('users', array('uid'))->condition('uid', $account->uid, '<>')->condition('mail', db_like($form_state['values']['mail']), 'LIKE')->range(0, 1)->execute()->fetchField()) {
+ if ((bool) db_select('users')->fields('users', array('uid'))->condition('uid', $account->uid, '<>')->condition('mail', db_like($mail), 'LIKE')->range(0, 1)->execute()->fetchField()) {
// Format error message dependent on whether the user is logged in or not.
if ($GLOBALS['user']->uid) {
- form_set_error('mail', t('The e-mail address %email is already taken.', array('%email' => $form_state['values']['mail'])));
+ form_set_error('mail', t('The e-mail address %email is already taken.', array('%email' => $mail)));
}
else {
- form_set_error('mail', t('The e-mail address %email is already registered. Have you forgotten your password?', array('%email' => $form_state['values']['mail'], '@password' => url('user/password'))));
+ form_set_error('mail', t('The e-mail address %email is already registered. Have you forgotten your password?', array('%email' => $mail, '@password' => url('user/password'))));
}
}
@@ -3462,8 +3433,8 @@ function theme_user_signature($variables) {
*/
function user_preferred_language($account, $default = NULL) {
$language_list = language_list();
- if (!empty($account->language) && isset($language_list[$account->language])) {
- return $language_list[$account->language];
+ if (!empty($account->preferred_langcode) && isset($language_list[$account->preferred_langcode])) {
+ return $language_list[$account->preferred_langcode];
}
else {
return $default ? $default : language_default();
diff --git a/core/modules/user/user.test b/core/modules/user/user.test
index 0c5f90f..81d3e07 100644
--- a/core/modules/user/user.test
+++ b/core/modules/user/user.test
@@ -166,7 +166,8 @@ class UserRegistrationTestCase extends DrupalWebTestCase {
$this->assertTrue(($new_user->created > REQUEST_TIME - 20 ), t('Correct creation time.'));
$this->assertEqual($new_user->status, variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) == USER_REGISTER_VISITORS ? 1 : 0, t('Correct status field.'));
$this->assertEqual($new_user->timezone, variable_get('date_default_timezone'), t('Correct time zone field.'));
- $this->assertEqual($new_user->language, '', t('Correct language field.'));
+ $this->assertEqual($new_user->langcode, '', t('Correct language field.'));
+ $this->assertEqual($new_user->preferred_langcode, '', t('Correct preferred language field.'));
$this->assertEqual($new_user->picture, '', t('Correct picture field.'));
$this->assertEqual($new_user->init, $mail, t('Correct init field.'));
}
@@ -222,7 +223,7 @@ class UserRegistrationTestCase extends DrupalWebTestCase {
// Check user fields.
$accounts = user_load_multiple(array(), array('name' => $name, 'mail' => $mail));
$new_user = reset($accounts);
- $this->assertEqual($new_user->test_user_field[LANGUAGE_NONE][0]['value'], $value, t('The field value was correclty saved.'));
+ $this->assertEqual($new_user->test_user_field[LANGUAGE_NOT_SPECIFIED][0]['value'], $value, t('The field value was correclty saved.'));
// Check that the 'add more' button works.
$field['cardinality'] = FIELD_CARDINALITY_UNLIMITED;
@@ -250,9 +251,9 @@ class UserRegistrationTestCase extends DrupalWebTestCase {
// Check user fields.
$accounts = user_load_multiple(array(), array('name' => $name, 'mail' => $mail));
$new_user = reset($accounts);
- $this->assertEqual($new_user->test_user_field[LANGUAGE_NONE][0]['value'], $value, t('@js : The field value was correclty saved.', array('@js' => $js)));
- $this->assertEqual($new_user->test_user_field[LANGUAGE_NONE][1]['value'], $value + 1, t('@js : The field value was correclty saved.', array('@js' => $js)));
- $this->assertEqual($new_user->test_user_field[LANGUAGE_NONE][2]['value'], $value + 2, t('@js : The field value was correclty saved.', array('@js' => $js)));
+ $this->assertEqual($new_user->test_user_field[LANGUAGE_NOT_SPECIFIED][0]['value'], $value, t('@js : The field value was correclty saved.', array('@js' => $js)));
+ $this->assertEqual($new_user->test_user_field[LANGUAGE_NOT_SPECIFIED][1]['value'], $value + 1, t('@js : The field value was correclty saved.', array('@js' => $js)));
+ $this->assertEqual($new_user->test_user_field[LANGUAGE_NOT_SPECIFIED][2]['value'], $value + 2, t('@js : The field value was correclty saved.', array('@js' => $js)));
}
}
}
@@ -292,20 +293,6 @@ class UserValidationTestCase extends DrupalWebTestCase {
$this->$test($result, $description . ' (' . $name . ')');
}
}
-
- // Mail validation. More extensive tests can be found at common.test
- function testMailAddresses() {
- $test_cases = array( // '' => array('', 'assert'),
- '' => array('Empty mail address', 'assertNotNull'),
- 'foo' => array('Invalid mail address', 'assertNotNull'),
- 'foo@example.com' => array('Valid mail address', 'assertNull'),
- );
- foreach ($test_cases as $name => $test_case) {
- list($description, $test) = $test_case;
- $result = user_validate_mail($name);
- $this->$test($result, $description . ' (' . $name . ')');
- }
- }
}
/**
@@ -455,6 +442,8 @@ class UserLoginTestCase extends DrupalWebTestCase {
* Test cancelling a user.
*/
class UserCancelTestCase extends DrupalWebTestCase {
+ protected $profile = 'standard';
+
public static function getInfo() {
return array(
'name' => 'Cancel account',
@@ -724,7 +713,7 @@ class UserCancelTestCase extends DrupalWebTestCase {
$node = $this->drupalCreateNode(array('uid' => $account->uid));
// Create comment.
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$edit = array();
$edit['subject'] = $this->randomName(8);
$edit['comment_body[' . $langcode . '][0][value]'] = $this->randomName(16);
@@ -862,10 +851,15 @@ class UserPictureTestCase extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp();
+ parent::setUp(array('image'));
// Enable user pictures.
variable_set('user_pictures', 1);
+ // Configure default user picture settings.
+ variable_set('user_picture_dimensions', '1024x1024');
+ variable_set('user_picture_file_size', '800');
+ variable_set('user_picture_style', 'thumbnail');
+
$this->user = $this->drupalCreateUser();
// Test if directories specified in settings exist in filesystem.
@@ -1198,6 +1192,10 @@ class UserAdminTestCase extends DrupalWebTestCase {
);
}
+ function setUp() {
+ parent::setUp(array('taxonomy'));
+ }
+
/**
* Registers a user and deletes it.
*/
@@ -1398,14 +1396,14 @@ class UserAccountLinksUnitTests extends DrupalWebTestCase {
// For a logged-in user, expect the secondary menu to have links for "My
// account" and "Log out".
$link = $this->xpath('//ul[@id=:menu_id]/li/a[contains(@href, :href) and text()=:text]', array(
- ':menu_id' => 'secondary-menu-links',
+ ':menu_id' => 'secondary-menu',
':href' => 'user',
':text' => 'My account',
));
$this->assertEqual(count($link), 1, 'My account link is in secondary menu.');
$link = $this->xpath('//ul[@id=:menu_id]/li/a[contains(@href, :href) and text()=:text]', array(
- ':menu_id' => 'secondary-menu-links',
+ ':menu_id' => 'secondary-menu',
':href' => 'user/logout',
':text' => 'Log out',
));
@@ -1416,7 +1414,7 @@ class UserAccountLinksUnitTests extends DrupalWebTestCase {
$this->drupalGet('');
// For a logged-out user, expect no secondary links.
- $element = $this->xpath('//ul[@id=:menu_id]', array(':menu_id' => 'secondary-menu-links'));
+ $element = $this->xpath('//ul[@id=:menu_id]', array(':menu_id' => 'secondary-menu'));
$this->assertEqual(count($element), 0, 'No secondary-menu for logged-out users.');
}
}
@@ -1433,6 +1431,26 @@ class UserBlocksUnitTests extends DrupalWebTestCase {
);
}
+ function setUp() {
+ parent::setUp(array('block'));
+
+ // Enable user login block.
+ db_merge('block')
+ ->key(array(
+ 'module' => 'user',
+ 'delta' => 'login',
+ 'theme' => variable_get('theme_default', 'stark'),
+ ))
+ ->fields(array(
+ 'status' => 1,
+ 'weight' => 0,
+ 'region' => 'sidebar_first',
+ 'pages' => '',
+ 'cache' => -1,
+ ))
+ ->execute();
+ }
+
/**
* Test the user login block.
*/
@@ -1692,12 +1710,32 @@ class UserSignatureTestCase extends DrupalWebTestCase {
// Enable user signatures.
variable_set('user_signatures', 1);
- // Prefetch text formats.
- $this->full_html_format = filter_format_load('full_html');
+ // Create Basic page node type.
+ $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
+
+ // Prefetch and create text formats.
$this->plain_text_format = filter_format_load('plain_text');
+ $filtered_html_format = array(
+ 'format' => 'filtered_html',
+ 'name' => 'Filtered HTML',
+ );
+ $this->filtered_html_format = (object) $filtered_html_format;
+ filter_format_save($this->filtered_html_format);
+
+ $full_html_format = array(
+ 'format' => 'full_html',
+ 'name' => 'Full HTML',
+ );
+ $this->full_html_format = (object) $full_html_format;
+ filter_format_save($this->full_html_format);
+
+ user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID, array(filter_permission_name($this->filtered_html_format)));
+ $this->checkPermissions(array(), TRUE);
+
// Create regular and administrative users.
- $this->web_user = $this->drupalCreateUser(array());
+ $this->web_user = $this->drupalCreateUser(array('post comments'));
+
$admin_permissions = array('administer comments');
foreach (filter_formats() as $format) {
if ($permission = filter_permission_name($format)) {
@@ -1733,7 +1771,7 @@ class UserSignatureTestCase extends DrupalWebTestCase {
$this->assertFieldByName('signature[format]', $edit['signature[format]'], 'Submitted signature format found.');
// Create a comment.
- $langcode = LANGUAGE_NONE;
+ $langcode = LANGUAGE_NOT_SPECIFIED;
$edit = array();
$edit['subject'] = $this->randomName(8);
$edit['comment_body[' . $langcode . '][0][value]'] = $this->randomName(16);
@@ -1956,6 +1994,10 @@ class UserUserSearchTestCase extends DrupalWebTestCase {
);
}
+ function setUp() {
+ parent::setUp(array('search'));
+ }
+
function testUserSearch() {
$user1 = $this->drupalCreateUser(array('access user profiles', 'search content', 'use advanced search'));
$this->drupalLogin($user1);
diff --git a/core/modules/user/user.tokens.inc b/core/modules/user/user.tokens.inc
index 76ec4a2..833e763 100644
--- a/core/modules/user/user.tokens.inc
+++ b/core/modules/user/user.tokens.inc
@@ -65,10 +65,10 @@ function user_tokens($type, $tokens, array $data = array(), array $options = arr
$url_options = array('absolute' => TRUE);
if (isset($options['language'])) {
$url_options['language'] = $options['language'];
- $language_code = $options['language']->langcode;
+ $langcode = $options['language']->langcode;
}
else {
- $language_code = NULL;
+ $langcode = NULL;
}
$sanitize = !empty($options['sanitize']);
@@ -103,12 +103,12 @@ function user_tokens($type, $tokens, array $data = array(), array $options = arr
// These tokens are default variations on the chained tokens handled below.
case 'last-login':
- $replacements[$original] = !empty($account->login) ? format_date($account->login, 'medium', '', NULL, $language_code) : t('never');
+ $replacements[$original] = !empty($account->login) ? format_date($account->login, 'medium', '', NULL, $langcode) : t('never');
break;
case 'created':
// In the case of user_presave the created date may not yet be set.
- $replacements[$original] = !empty($account->created) ? format_date($account->created, 'medium', '', NULL, $language_code) : t('not yet created');
+ $replacements[$original] = !empty($account->created) ? format_date($account->created, 'medium', '', NULL, $langcode) : t('not yet created');
break;
}
}
diff --git a/core/themes/bartik/css/style-rtl.css b/core/themes/bartik/css/style-rtl.css
index 48f64ab..90638eb 100644
--- a/core/themes/bartik/css/style-rtl.css
+++ b/core/themes/bartik/css/style-rtl.css
@@ -1,4 +1,3 @@
-
/* ------------------ Reset Styles ------------------ */
caption,
@@ -125,7 +124,7 @@ ul.tips {
.comment ul.links li {
padding: 0 0 0.5em;
}
-.comment-unpublished {
+.comment.unpublished {
margin-left: 5px;
margin-right: 0;
padding: 5px 5px 5px 2px;
@@ -259,6 +258,13 @@ ul.action-links li a {
.poll .total {
text-align: left;
}
+.poll .choice-title {
+ clear: left;
+}
+.poll .percent {
+ float: left;
+ text-align: left;
+}
/* ---------- Color Form ----------- */
diff --git a/core/themes/bartik/css/style.css b/core/themes/bartik/css/style.css
index 3413e17..8fbe5aa 100644
--- a/core/themes/bartik/css/style.css
+++ b/core/themes/bartik/css/style.css
@@ -1,4 +1,3 @@
-
/* ---------- Overall Specifications ---------- */
body {
@@ -229,13 +228,8 @@ table ul.links li {
margin: 0;
padding: 0 0 0.25em 1em; /* LTR */
}
-.contextual-links-wrapper {
- font-size: small !important;
-}
-ul.contextual-links {
+.contextual-region .contextual .contextual-links a {
font-size: 0.923em;
-}
-.contextual-links-wrapper a {
text-shadow: 0 0 0 !important;
}
.item-list .pager {
@@ -721,11 +715,11 @@ ul.links {
.comment ul.links li {
padding: 0 0.5em 0 0; /* LTR */
}
-.comment-unpublished {
+.comment.unpublished {
margin-right: 5px; /* LTR */
padding: 5px 2px 5px 5px; /* LTR */
}
-.comment-unpublished .comment-text .comment-arrow {
+.comment.unpublished .comment-text .comment-arrow {
border-left: 1px solid #fff4f4;
border-right: 1px solid #fff4f4;
}
@@ -1195,6 +1189,8 @@ select.form-select {
}
input.form-text,
input.form-tel,
+input.form-email,
+input.form-url,
textarea.form-textarea,
select.form-select {
border: 1px solid #ccc;
@@ -1247,13 +1243,6 @@ input.form-submit:focus {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
-.contact-form .resizable-textarea .grippie {
- width: 76%;
- -moz-border-radius-bottomleft: 4px;
- -moz-border-radius-bottomright: 4px;
- border-bottom-left-radius: 4px;
- border-bottom-right-radius: 4px;
-}
/* Disabled form elements */
input.form-button-disabled,
@@ -1267,10 +1256,6 @@ input.form-button-disabled:active,
border-color: #bbb;
color: #717171;
}
-.form-disabled .grippie {
- background-color: #ededed;
- border-color: #bbb;
-}
.form-disabled label {
color: #717171;
}
@@ -1558,12 +1543,11 @@ div.admin-panel .description {
font-style: italic;
margin-bottom: 3em;
margin-top: -3.2em;
- float: right;
- text-align: right;
+ float: right; /* LTR */
+ text-align: right; /* LTR */
}
.poll .choice-title {
- clear: right;
- margin-right: 2.25em;
+ clear: right; /* LTR */
}
.poll .total {
font-size: 0.929em;
diff --git a/core/themes/bartik/templates/comment.tpl.php b/core/themes/bartik/templates/comment.tpl.php
index 553fb53..27e8a46 100644
--- a/core/themes/bartik/templates/comment.tpl.php
+++ b/core/themes/bartik/templates/comment.tpl.php
@@ -23,19 +23,19 @@
* - $picture: Authors picture.
* - $signature: Authors signature.
* - $status: Comment status. Possible values are:
- * comment-unpublished, comment-published or comment-preview.
+ * unpublished, published, or preview.
* - $title: Linked title.
* - $classes: String of classes that can be used to style contextually through
* CSS. It can be manipulated through the variable $classes_array from
* preprocess functions. The default values can be one or more of the following:
- * - comment: The current template type, i.e., "theming hook".
- * - comment-by-anonymous: Comment by an unregistered user.
- * - comment-by-node-author: Comment by the author of the parent node.
- * - comment-preview: When previewing a new or edited comment.
+ * - comment: The current template type; e.g., 'theming hook'.
+ * - by-anonymous: Comment by an unregistered user.
+ * - by-node-author: Comment by the author of the parent node.
+ * - preview: When previewing a new or edited comment.
* The following applies only to viewers who are registered users:
- * - comment-unpublished: An unpublished comment visible only to administrators.
- * - comment-by-viewer: Comment by the user currently viewing the page.
- * - comment-new: New comment since last the visit.
+ * - unpublished: An unpublished comment visible only to administrators.
+ * - by-viewer: Comment by the user currently viewing the page.
+ * - new: New comment since the last visit.
* - $title_prefix (array): An array containing additional output populated by
* modules, intended to be displayed in front of the main title tag that
* appears in the template.
diff --git a/core/themes/seven/style.css b/core/themes/seven/style.css
index 66914f6..f5c4aab 100644
--- a/core/themes/seven/style.css
+++ b/core/themes/seven/style.css
@@ -602,6 +602,8 @@ div.teaser-checkbox .form-item,
.form-disabled input.form-autocomplete,
.form-disabled input.form-text,
.form-disabled input.form-tel,
+.form-disabled input.form-email,
+.form-disabled input.form-url,
.form-disabled input.form-file,
.form-disabled textarea.form-textarea,
.form-disabled select.form-select {
@@ -689,6 +691,8 @@ input.form-button-disabled:active {
input.form-autocomplete,
input.form-text,
input.form-tel,
+input.form-email,
+input.form-url,
input.form-file,
textarea.form-textarea,
select.form-select {
@@ -703,6 +707,8 @@ select.form-select {
}
input.form-text:focus,
input.form-tel:focus,
+input.form-email:focus,
+input.form-url:focus,
input.form-file:focus,
textarea.form-textarea:focus,
select.form-select:focus {
diff --git a/core/update.php b/core/update.php
index 4d74c7e..3d858a2 100644
--- a/core/update.php
+++ b/core/update.php
@@ -26,8 +26,8 @@ define('DRUPAL_ROOT', getcwd());
// The minimum version is specified explicitly, as DRUPAL_MINIMUM_PHP is not
// yet available. It is defined in bootstrap.inc, but it is not possible to
// load that file yet as it would cause a fatal error on older versions of PHP.
-if (version_compare(PHP_VERSION, '5.3.2') < 0) {
- print 'Your PHP installation is too old. Drupal requires at least PHP 5.3.2. See the system requirements page for more information.';
+if (version_compare(PHP_VERSION, '5.3.3') < 0) {
+ print 'Your PHP installation is too old. Drupal requires at least PHP 5.3.3. See the system requirements page for more information.';
exit;
}
@@ -374,6 +374,7 @@ require_once DRUPAL_ROOT . '/core/includes/update.inc';
require_once DRUPAL_ROOT . '/core/includes/common.inc';
require_once DRUPAL_ROOT . '/core/includes/file.inc';
require_once DRUPAL_ROOT . '/core/includes/unicode.inc';
+require_once DRUPAL_ROOT . '/core/includes/schema.inc';
update_prepare_d8_bootstrap();
// Determine if the current user has access to run update.php.
diff --git a/core/vendor/Symfony/Component/EventDispatcher/Event.php b/core/vendor/Symfony/Component/EventDispatcher/Event.php
new file mode 100644
index 0000000..fc2c0d4
--- /dev/null
+++ b/core/vendor/Symfony/Component/EventDispatcher/Event.php
@@ -0,0 +1,121 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\EventDispatcher;
+
+/**
+ * Event is the base class for classes containing event data.
+ *
+ * This class contains no event data. It is used by events that do not pass
+ * state information to an event handler when an event is raised.
+ *
+ * You can call the method stopPropagation() to abort the execution of
+ * further listeners in your event listener.
+ *
+ * @author Guilherme Blanco
+ * @author Jonathan Wage
+ * @author Roman Borschel
+ * @author Bernhard Schussek
+ *
+ * @api
+ */
+class Event
+{
+ /**
+ * @var Boolean Whether no further event listeners should be triggered
+ */
+ private $propagationStopped = false;
+
+ /**
+ * @var EventDispatcher Dispatcher that dispatched this event
+ */
+ private $dispatcher;
+
+ /**
+ * @var string This event's name
+ */
+ private $name;
+
+ /**
+ * Returns whether further event listeners should be triggered.
+ *
+ * @see Event::stopPropagation
+ * @return Boolean Whether propagation was already stopped for this event.
+ *
+ * @api
+ */
+ public function isPropagationStopped()
+ {
+ return $this->propagationStopped;
+ }
+
+ /**
+ * Stops the propagation of the event to further event listeners.
+ *
+ * If multiple event listeners are connected to the same event, no
+ * further event listener will be triggered once any trigger calls
+ * stopPropagation().
+ *
+ * @api
+ */
+ public function stopPropagation()
+ {
+ $this->propagationStopped = true;
+ }
+
+ /**
+ * Stores the EventDispatcher that dispatches this Event
+ *
+ * @param EventDispatcher $dispatcher
+ *
+ * @api
+ */
+ public function setDispatcher(EventDispatcher $dispatcher)
+ {
+ $this->dispatcher = $dispatcher;
+ }
+
+ /**
+ * Returns the EventDispatcher that dispatches this Event
+ *
+ * @return EventDispatcher
+ *
+ * @api
+ */
+ public function getDispatcher()
+ {
+ return $this->dispatcher;
+ }
+
+ /**
+ * Gets the event's name.
+ *
+ * @return string
+ *
+ * @api
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Sets the event's name property.
+ *
+ * @param string $name The event name.
+ *
+ * @api
+ */
+ public function setName($name)
+ {
+ $this->name = $name;
+ }
+}
diff --git a/core/vendor/Symfony/Component/EventDispatcher/EventDispatcher.php b/core/vendor/Symfony/Component/EventDispatcher/EventDispatcher.php
new file mode 100644
index 0000000..0c98301
--- /dev/null
+++ b/core/vendor/Symfony/Component/EventDispatcher/EventDispatcher.php
@@ -0,0 +1,183 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\EventDispatcher;
+
+/**
+ * The EventDispatcherInterface is the central point of Symfony's event listener system.
+ *
+ * Listeners are registered on the manager and events are dispatched through the
+ * manager.
+ *
+ * @author Guilherme Blanco
+ * @author Jonathan Wage
+ * @author Roman Borschel
+ * @author Bernhard Schussek
+ * @author Fabien Potencier
+ * @author Jordi Boggiano
+ * @author Jordan Alliot
+ *
+ * @api
+ */
+class EventDispatcher implements EventDispatcherInterface
+{
+ private $listeners = array();
+ private $sorted = array();
+
+ /**
+ * @see EventDispatcherInterface::dispatch
+ *
+ * @api
+ */
+ public function dispatch($eventName, Event $event = null)
+ {
+ if (!isset($this->listeners[$eventName])) {
+ return;
+ }
+
+ if (null === $event) {
+ $event = new Event();
+ }
+
+ $event->setDispatcher($this);
+ $event->setName($eventName);
+
+ $this->doDispatch($this->getListeners($eventName), $eventName, $event);
+ }
+
+ /**
+ * @see EventDispatcherInterface::getListeners
+ */
+ public function getListeners($eventName = null)
+ {
+ if (null !== $eventName) {
+ if (!isset($this->sorted[$eventName])) {
+ $this->sortListeners($eventName);
+ }
+
+ return $this->sorted[$eventName];
+ }
+
+ foreach (array_keys($this->listeners) as $eventName) {
+ if (!isset($this->sorted[$eventName])) {
+ $this->sortListeners($eventName);
+ }
+ }
+
+ return $this->sorted;
+ }
+
+ /**
+ * @see EventDispatcherInterface::hasListeners
+ */
+ public function hasListeners($eventName = null)
+ {
+ return (Boolean) count($this->getListeners($eventName));
+ }
+
+ /**
+ * @see EventDispatcherInterface::addListener
+ *
+ * @api
+ */
+ public function addListener($eventName, $listener, $priority = 0)
+ {
+ $this->listeners[$eventName][$priority][] = $listener;
+ unset($this->sorted[$eventName]);
+ }
+
+ /**
+ * @see EventDispatcherInterface::removeListener
+ */
+ public function removeListener($eventName, $listener)
+ {
+ if (!isset($this->listeners[$eventName])) {
+ return;
+ }
+
+ foreach ($this->listeners[$eventName] as $priority => $listeners) {
+ if (false !== ($key = array_search($listener, $listeners))) {
+ unset($this->listeners[$eventName][$priority][$key], $this->sorted[$eventName]);
+ }
+ }
+ }
+
+ /**
+ * @see EventDispatcherInterface::addSubscriber
+ *
+ * @api
+ */
+ public function addSubscriber(EventSubscriberInterface $subscriber)
+ {
+ foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
+ if (is_string($params)) {
+ $this->addListener($eventName, array($subscriber, $params));
+ } elseif (is_string($params[0])) {
+ $this->addListener($eventName, array($subscriber, $params[0]), $params[1]);
+ } else {
+ foreach ($params as $listener) {
+ $this->addListener($eventName, array($subscriber, $listener[0]), isset($listener[1]) ? $listener[1] : 0);
+ }
+ }
+ }
+ }
+
+ /**
+ * @see EventDispatcherInterface::removeSubscriber
+ */
+ public function removeSubscriber(EventSubscriberInterface $subscriber)
+ {
+ foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
+ if (is_array($params) && is_array($params[0])) {
+ foreach ($params as $listener) {
+ $this->removeListener($eventName, array($subscriber, $listener[0]));
+ }
+ } else {
+ $this->removeListener($eventName, array($subscriber, is_string($params) ? $params : $params[0]));
+ }
+ }
+ }
+
+ /**
+ * Triggers the listeners of an event.
+ *
+ * This method can be overridden to add functionality that is executed
+ * for each listener.
+ *
+ * @param array[callback] $listeners The event listeners.
+ * @param string $eventName The name of the event to dispatch.
+ * @param Event $event The event object to pass to the event handlers/listeners.
+ */
+ protected function doDispatch($listeners, $eventName, Event $event)
+ {
+ foreach ($listeners as $listener) {
+ call_user_func($listener, $event);
+ if ($event->isPropagationStopped()) {
+ break;
+ }
+ }
+ }
+
+ /**
+ * Sorts the internal list of listeners for the given event by priority.
+ *
+ * @param string $eventName The name of the event.
+ */
+ private function sortListeners($eventName)
+ {
+ $this->sorted[$eventName] = array();
+
+ if (isset($this->listeners[$eventName])) {
+ krsort($this->listeners[$eventName]);
+ $this->sorted[$eventName] = call_user_func_array('array_merge', $this->listeners[$eventName]);
+ }
+ }
+}
diff --git a/core/vendor/Symfony/Component/EventDispatcher/EventDispatcherInterface.php b/core/vendor/Symfony/Component/EventDispatcher/EventDispatcherInterface.php
new file mode 100644
index 0000000..25ebbdc
--- /dev/null
+++ b/core/vendor/Symfony/Component/EventDispatcher/EventDispatcherInterface.php
@@ -0,0 +1,94 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\EventDispatcher;
+
+/**
+ * The EventDispatcherInterface is the central point of Symfony's event listener system.
+ * Listeners are registered on the manager and events are dispatched through the
+ * manager.
+ *
+ * @author Bernhard Schussek
+ *
+ * @api
+ */
+interface EventDispatcherInterface
+{
+ /**
+ * Dispatches an event to all registered listeners.
+ *
+ * @param string $eventName The name of the event to dispatch. The name of
+ * the event is the name of the method that is
+ * invoked on listeners.
+ * @param Event $event The event to pass to the event handlers/listeners.
+ * If not supplied, an empty Event instance is created.
+ *
+ * @api
+ */
+ function dispatch($eventName, Event $event = null);
+
+ /**
+ * Adds an event listener that listens on the specified events.
+ *
+ * @param string $eventName The event to listen on
+ * @param callable $listener The listener
+ * @param integer $priority The higher this value, the earlier an event
+ * listener will be triggered in the chain (defaults to 0)
+ *
+ * @api
+ */
+ function addListener($eventName, $listener, $priority = 0);
+
+ /**
+ * Adds an event subscriber. The subscriber is asked for all the events he is
+ * interested in and added as a listener for these events.
+ *
+ * @param EventSubscriberInterface $subscriber The subscriber.
+ *
+ * @api
+ */
+ function addSubscriber(EventSubscriberInterface $subscriber);
+
+ /**
+ * Removes an event listener from the specified events.
+ *
+ * @param string|array $eventName The event(s) to remove a listener from.
+ * @param object $listener The listener object to remove.
+ */
+ function removeListener($eventName, $listener);
+
+ /**
+ * Removes an event subscriber.
+ *
+ * @param EventSubscriberInterface $subscriber The subscriber.
+ */
+ function removeSubscriber(EventSubscriberInterface $subscriber);
+
+ /**
+ * Gets the listeners of a specific event or all listeners.
+ *
+ * @param string $eventName The name of the event.
+ *
+ * @return array The event listeners for the specified event, or all event
+ * listeners by event name.
+ */
+ function getListeners($eventName = null);
+
+ /**
+ * Checks whether an event has any registered listeners.
+ *
+ * @param string $eventName The name of the event.
+ *
+ * @return Boolean TRUE if the specified event has any listeners, FALSE
+ * otherwise.
+ */
+ function hasListeners($eventName = null);
+}
diff --git a/core/vendor/Symfony/Component/EventDispatcher/EventSubscriberInterface.php b/core/vendor/Symfony/Component/EventDispatcher/EventSubscriberInterface.php
new file mode 100644
index 0000000..1e85b98
--- /dev/null
+++ b/core/vendor/Symfony/Component/EventDispatcher/EventSubscriberInterface.php
@@ -0,0 +1,50 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\EventDispatcher;
+
+/**
+ * An EventSubscriber knows himself what events he is interested in.
+ * If an EventSubscriber is added to an EventDispatcherInterface, the manager invokes
+ * {@link getSubscribedEvents} and registers the subscriber as a listener for all
+ * returned events.
+ *
+ * @author Guilherme Blanco
+ * @author Jonathan Wage
+ * @author Roman Borschel
+ * @author Bernhard Schussek
+ *
+ * @api
+ */
+interface EventSubscriberInterface
+{
+ /**
+ * Returns an array of event names this subscriber wants to listen to.
+ *
+ * The array keys are event names and the value can be:
+ *
+ * * The method name to call (priority defaults to 0)
+ * * An array composed of the method name to call and the priority
+ * * An array of arrays composed of the method names to call and respective
+ * priorities, or 0 if unset
+ *
+ * For instance:
+ *
+ * * array('eventName' => 'methodName')
+ * * array('eventName' => array('methodName', $priority))
+ * * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
+ *
+ * @return array The event names to listen to
+ *
+ * @api
+ */
+ static function getSubscribedEvents();
+}
diff --git a/core/vendor/Symfony/Component/EventDispatcher/LICENSE b/core/vendor/Symfony/Component/EventDispatcher/LICENSE
new file mode 100644
index 0000000..89df448
--- /dev/null
+++ b/core/vendor/Symfony/Component/EventDispatcher/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2004-2011 Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/core/vendor/Symfony/Component/EventDispatcher/README.md b/core/vendor/Symfony/Component/EventDispatcher/README.md
new file mode 100644
index 0000000..9427d75
--- /dev/null
+++ b/core/vendor/Symfony/Component/EventDispatcher/README.md
@@ -0,0 +1,23 @@
+EventDispatcher Component
+=========================
+
+EventDispatcher implements a lightweight version of the Observer design
+pattern.
+
+ use Symfony\Component\EventDispatcher\EventDispatcher;
+ use Symfony\Component\EventDispatcher\Event;
+
+ $dispatcher = new EventDispatcher();
+
+ $dispatcher->addListener('event_name', function (Event $event) {
+ // ...
+ });
+
+ $dispatcher->dispatch('event_name');
+
+Resources
+---------
+
+Unit tests:
+
+https://github.com/symfony/symfony/tree/master/tests/Symfony/Tests/Component/EventDispatcher
diff --git a/core/vendor/Symfony/Component/EventDispatcher/composer.json b/core/vendor/Symfony/Component/EventDispatcher/composer.json
new file mode 100644
index 0000000..b9ea291
--- /dev/null
+++ b/core/vendor/Symfony/Component/EventDispatcher/composer.json
@@ -0,0 +1,26 @@
+{
+ "name": "symfony/event-dispatcher",
+ "type": "library",
+ "description": "Symfony EventDispatcher Component",
+ "keywords": [],
+ "homepage": "http://symfony.com",
+ "version": "2.1.0",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "http://symfony.com/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.2"
+ },
+ "autoload": {
+ "psr-0": { "Symfony\\Component\\EventDispatcher": "" }
+ },
+ "target-dir": "Symfony/Component/EventDispatcher"
+}
diff --git a/core/vendor/Symfony/Component/HttpKernel/Bundle/Bundle.php b/core/vendor/Symfony/Component/HttpKernel/Bundle/Bundle.php
new file mode 100644
index 0000000..494feab
--- /dev/null
+++ b/core/vendor/Symfony/Component/HttpKernel/Bundle/Bundle.php
@@ -0,0 +1,194 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\Bundle;
+
+use Symfony\Component\DependencyInjection\ContainerAware;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Container;
+use Symfony\Component\Console\Application;
+use Symfony\Component\Finder\Finder;
+
+/**
+ * An implementation of BundleInterface that adds a few conventions
+ * for DependencyInjection extensions and Console commands.
+ *
+ * @author Fabien Potencier
+ *
+ * @api
+ */
+abstract class Bundle extends ContainerAware implements BundleInterface
+{
+ protected $name;
+ protected $reflected;
+ protected $extension;
+
+ /**
+ * Boots the Bundle.
+ */
+ public function boot()
+ {
+ }
+
+ /**
+ * Shutdowns the Bundle.
+ */
+ public function shutdown()
+ {
+ }
+
+ /**
+ * Builds the bundle.
+ *
+ * It is only ever called once when the cache is empty.
+ *
+ * This method can be overridden to register compilation passes,
+ * other extensions, ...
+ *
+ * @param ContainerBuilder $container A ContainerBuilder instance
+ */
+ public function build(ContainerBuilder $container)
+ {
+ }
+
+ /**
+ * Returns the bundle's container extension.
+ *
+ * @return ExtensionInterface|null The container extension
+ *
+ * @api
+ */
+ public function getContainerExtension()
+ {
+ if (null === $this->extension) {
+ $basename = preg_replace('/Bundle$/', '', $this->getName());
+
+ $class = $this->getNamespace().'\\DependencyInjection\\'.$basename.'Extension';
+ if (class_exists($class)) {
+ $extension = new $class();
+
+ // check naming convention
+ $expectedAlias = Container::underscore($basename);
+ if ($expectedAlias != $extension->getAlias()) {
+ throw new \LogicException(sprintf(
+ 'The extension alias for the default extension of a '.
+ 'bundle must be the underscored version of the '.
+ 'bundle name ("%s" instead of "%s")',
+ $expectedAlias, $extension->getAlias()
+ ));
+ }
+
+ $this->extension = $extension;
+ } else {
+ $this->extension = false;
+ }
+ }
+
+ if ($this->extension) {
+ return $this->extension;
+ }
+ }
+
+ /**
+ * Gets the Bundle namespace.
+ *
+ * @return string The Bundle namespace
+ *
+ * @api
+ */
+ public function getNamespace()
+ {
+ if (null === $this->reflected) {
+ $this->reflected = new \ReflectionObject($this);
+ }
+
+ return $this->reflected->getNamespaceName();
+ }
+
+ /**
+ * Gets the Bundle directory path.
+ *
+ * @return string The Bundle absolute path
+ *
+ * @api
+ */
+ public function getPath()
+ {
+ if (null === $this->reflected) {
+ $this->reflected = new \ReflectionObject($this);
+ }
+
+ return dirname($this->reflected->getFileName());
+ }
+
+ /**
+ * Returns the bundle parent name.
+ *
+ * @return string The Bundle parent name it overrides or null if no parent
+ *
+ * @api
+ */
+ public function getParent()
+ {
+ return null;
+ }
+
+ /**
+ * Returns the bundle name (the class short name).
+ *
+ * @return string The Bundle name
+ *
+ * @api
+ */
+ final public function getName()
+ {
+ if (null !== $this->name) {
+ return $this->name;
+ }
+
+ $name = get_class($this);
+ $pos = strrpos($name, '\\');
+
+ return $this->name = false === $pos ? $name : substr($name, $pos + 1);
+ }
+
+ /**
+ * Finds and registers Commands.
+ *
+ * Override this method if your bundle commands do not follow the conventions:
+ *
+ * * Commands are in the 'Command' sub-directory
+ * * Commands extend Symfony\Component\Console\Command\Command
+ *
+ * @param Application $application An Application instance
+ */
+ public function registerCommands(Application $application)
+ {
+ if (!$dir = realpath($this->getPath().'/Command')) {
+ return;
+ }
+
+ $finder = new Finder();
+ $finder->files()->name('*Command.php')->in($dir);
+
+ $prefix = $this->getNamespace().'\\Command';
+ foreach ($finder as $file) {
+ $ns = $prefix;
+ if ($relativePath = $file->getRelativePath()) {
+ $ns .= '\\'.strtr($relativePath, '/', '\\');
+ }
+ $r = new \ReflectionClass($ns.'\\'.$file->getBasename('.php'));
+ if ($r->isSubclassOf('Symfony\\Component\\Console\\Command\\Command') && !$r->isAbstract()) {
+ $application->add($r->newInstance());
+ }
+ }
+ }
+}
diff --git a/core/vendor/Symfony/Component/HttpKernel/Bundle/BundleInterface.php b/core/vendor/Symfony/Component/HttpKernel/Bundle/BundleInterface.php
new file mode 100644
index 0000000..99d591f
--- /dev/null
+++ b/core/vendor/Symfony/Component/HttpKernel/Bundle/BundleInterface.php
@@ -0,0 +1,96 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\Bundle;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * BundleInterface.
+ *
+ * @author Fabien Potencier
+ *
+ * @api
+ */
+interface BundleInterface
+{
+ /**
+ * Boots the Bundle.
+ *
+ * @api
+ */
+ function boot();
+
+ /**
+ * Shutdowns the Bundle.
+ *
+ * @api
+ */
+ function shutdown();
+
+ /**
+ * Builds the bundle.
+ *
+ * It is only ever called once when the cache is empty.
+ *
+ * @param ContainerBuilder $container A ContainerBuilder instance
+ *
+ * @api
+ */
+ function build(ContainerBuilder $container);
+
+ /**
+ * Returns the container extension that should be implicitly loaded.
+ *
+ * @return ExtensionInterface|null The default extension or null if there is none
+ *
+ * @api
+ */
+ function getContainerExtension();
+
+ /**
+ * Returns the bundle parent name.
+ *
+ * @return string The Bundle parent name it overrides or null if no parent
+ *
+ * @api
+ */
+ function getParent();
+
+ /**
+ * Returns the bundle name (the class short name).
+ *
+ * @return string The Bundle name
+ *
+ * @api
+ */
+ function getName();
+
+ /**
+ * Gets the Bundle namespace.
+ *
+ * @return string The Bundle namespace
+ *
+ * @api
+ */
+ function getNamespace();
+
+ /**
+ * Gets the Bundle directory path.
+ *
+ * The path should always be returned as a Unix path (with /).
+ *
+ * @return string The Bundle absolute path
+ *
+ * @api
+ */
+ function getPath();
+}
diff --git a/core/vendor/Symfony/Component/HttpKernel/CacheClearer/CacheClearerInterface.php b/core/vendor/Symfony/Component/HttpKernel/CacheClearer/CacheClearerInterface.php
new file mode 100644
index 0000000..1588b67
--- /dev/null
+++ b/core/vendor/Symfony/Component/HttpKernel/CacheClearer/CacheClearerInterface.php
@@ -0,0 +1,27 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\CacheClearer;
+
+/**
+ * CacheClearerInterface.
+ *
+ * @author Dustin Dobervich
+ */
+interface CacheClearerInterface
+{
+ /**
+ * Clears any caches necessary.
+ *
+ * @param string $cacheDir The cache directory.
+ */
+ function clear($cacheDir);
+}
diff --git a/core/vendor/Symfony/Component/HttpKernel/CacheClearer/ChainCacheClearer.php b/core/vendor/Symfony/Component/HttpKernel/CacheClearer/ChainCacheClearer.php
new file mode 100644
index 0000000..7b492d0
--- /dev/null
+++ b/core/vendor/Symfony/Component/HttpKernel/CacheClearer/ChainCacheClearer.php
@@ -0,0 +1,55 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\CacheClearer;
+
+/**
+ * ChainCacheClearer.
+ *
+ * @author Dustin Dobervich
+ */
+class ChainCacheClearer implements CacheClearerInterface
+{
+ /**
+ * @var array $clearers
+ */
+ protected $clearers;
+
+ /**
+ * Constructs a new instance of ChainCacheClearer.
+ *
+ * @param array $clearers The initial clearers.
+ */
+ public function __construct(array $clearers = array())
+ {
+ $this->clearers = $clearers;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function clear($cacheDir)
+ {
+ foreach ($this->clearers as $clearer) {
+ $clearer->clear($cacheDir);
+ }
+ }
+
+ /**
+ * Adds a cache clearer to the aggregate.
+ *
+ * @param CacheClearerInterface $clearer
+ */
+ public function add(CacheClearerInterface $clearer)
+ {
+ $this->clearers[] = $clearer;
+ }
+}
diff --git a/core/vendor/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmer.php b/core/vendor/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmer.php
new file mode 100644
index 0000000..758fb1e
--- /dev/null
+++ b/core/vendor/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmer.php
@@ -0,0 +1,32 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\CacheWarmer;
+
+/**
+ * Abstract cache warmer that knows how to write a file to the cache.
+ *
+ * @author Fabien Potencier
+ */
+abstract class CacheWarmer implements CacheWarmerInterface
+{
+ protected function writeCacheFile($file, $content)
+ {
+ $tmpFile = tempnam(dirname($file), basename($file));
+ if (false !== @file_put_contents($tmpFile, $content) && @rename($tmpFile, $file)) {
+ chmod($file, 0644);
+
+ return;
+ }
+
+ throw new \RuntimeException(sprintf('Failed to write cache file "%s".', $file));
+ }
+}
diff --git a/core/vendor/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmerAggregate.php b/core/vendor/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmerAggregate.php
new file mode 100644
index 0000000..eb26ac5
--- /dev/null
+++ b/core/vendor/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmerAggregate.php
@@ -0,0 +1,73 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\CacheWarmer;
+
+/**
+ * Aggregates several cache warmers into a single one.
+ *
+ * @author Fabien Potencier
+ */
+class CacheWarmerAggregate implements CacheWarmerInterface
+{
+ protected $warmers;
+ protected $optionalsEnabled;
+
+ public function __construct(array $warmers = array())
+ {
+ $this->setWarmers($warmers);
+ $this->optionalsEnabled = false;
+ }
+
+ public function enableOptionalWarmers()
+ {
+ $this->optionalsEnabled = true;
+ }
+
+ /**
+ * Warms up the cache.
+ *
+ * @param string $cacheDir The cache directory
+ */
+ public function warmUp($cacheDir)
+ {
+ foreach ($this->warmers as $warmer) {
+ if (!$this->optionalsEnabled && $warmer->isOptional()) {
+ continue;
+ }
+
+ $warmer->warmUp($cacheDir);
+ }
+ }
+
+ /**
+ * Checks whether this warmer is optional or not.
+ *
+ * @return Boolean always true
+ */
+ public function isOptional()
+ {
+ return false;
+ }
+
+ public function setWarmers(array $warmers)
+ {
+ $this->warmers = array();
+ foreach ($warmers as $warmer) {
+ $this->add($warmer);
+ }
+ }
+
+ public function add(CacheWarmerInterface $warmer)
+ {
+ $this->warmers[] = $warmer;
+ }
+}
diff --git a/core/vendor/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmerInterface.php b/core/vendor/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmerInterface.php
new file mode 100644
index 0000000..478cdc9
--- /dev/null
+++ b/core/vendor/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmerInterface.php
@@ -0,0 +1,32 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\CacheWarmer;
+
+/**
+ * Interface for classes able to warm up the cache.
+ *
+ * @author Fabien Potencier
+ */
+interface CacheWarmerInterface extends WarmableInterface
+{
+ /**
+ * Checks whether this warmer is optional or not.
+ *
+ * Optional warmers can be ignored on certain conditions.
+ *
+ * A warmer should return true if the cache can be
+ * generated incrementally and on-demand.
+ *
+ * @return Boolean true if the warmer is optional, false otherwise
+ */
+ function isOptional();
+}
diff --git a/core/vendor/Symfony/Component/HttpKernel/CacheWarmer/WarmableInterface.php b/core/vendor/Symfony/Component/HttpKernel/CacheWarmer/WarmableInterface.php
new file mode 100644
index 0000000..0476161
--- /dev/null
+++ b/core/vendor/Symfony/Component/HttpKernel/CacheWarmer/WarmableInterface.php
@@ -0,0 +1,27 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\CacheWarmer;
+
+/**
+ * Interface for classes that support warming their cache.
+ *
+ * @author Fabien Potencier
+ */
+interface WarmableInterface
+{
+ /**
+ * Warms up the cache.
+ *
+ * @param string $cacheDir The cache directory
+ */
+ function warmUp($cacheDir);
+}
diff --git a/core/vendor/Symfony/Component/HttpKernel/Client.php b/core/vendor/Symfony/Component/HttpKernel/Client.php
new file mode 100644
index 0000000..ff93bf7
--- /dev/null
+++ b/core/vendor/Symfony/Component/HttpKernel/Client.php
@@ -0,0 +1,184 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel;
+
+use Symfony\Component\HttpFoundation\File\UploadedFile;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\BrowserKit\Client as BaseClient;
+use Symfony\Component\BrowserKit\Request as DomRequest;
+use Symfony\Component\BrowserKit\Response as DomResponse;
+use Symfony\Component\BrowserKit\Cookie as DomCookie;
+use Symfony\Component\BrowserKit\History;
+use Symfony\Component\BrowserKit\CookieJar;
+use Symfony\Component\HttpKernel\TerminableInterface;
+
+/**
+ * Client simulates a browser and makes requests to a Kernel object.
+ *
+ * @author Fabien Potencier
+ *
+ * @api
+ */
+class Client extends BaseClient
+{
+ protected $kernel;
+
+ /**
+ * Constructor.
+ *
+ * @param HttpKernelInterface $kernel An HttpKernel instance
+ * @param array $server The server parameters (equivalent of $_SERVER)
+ * @param History $history A History instance to store the browser history
+ * @param CookieJar $cookieJar A CookieJar instance to store the cookies
+ */
+ public function __construct(HttpKernelInterface $kernel, array $server = array(), History $history = null, CookieJar $cookieJar = null)
+ {
+ $this->kernel = $kernel;
+
+ parent::__construct($server, $history, $cookieJar);
+
+ $this->followRedirects = false;
+ }
+
+ /**
+ * Makes a request.
+ *
+ * @param Request $request A Request instance
+ *
+ * @return Response A Response instance
+ */
+ protected function doRequest($request)
+ {
+ $response = $this->kernel->handle($request);
+
+ if ($this->kernel instanceof TerminableInterface) {
+ $this->kernel->terminate($request, $response);
+ }
+
+ return $response;
+ }
+
+ /**
+ * Returns the script to execute when the request must be insulated.
+ *
+ * @param Request $request A Request instance
+ */
+ protected function getScript($request)
+ {
+ $kernel = str_replace("'", "\\'", serialize($this->kernel));
+ $request = str_replace("'", "\\'", serialize($request));
+
+ $r = new \ReflectionClass('\\Symfony\\Component\\ClassLoader\\UniversalClassLoader');
+ $requirePath = str_replace("'", "\\'", $r->getFileName());
+
+ $symfonyPath = str_replace("'", "\\'", realpath(__DIR__.'/../../..'));
+
+ return <<registerNamespaces(array('Symfony' => '$symfonyPath'));
+\$loader->register();
+
+\$kernel = unserialize('$kernel');
+echo serialize(\$kernel->handle(unserialize('$request')));
+EOF;
+ }
+
+ /**
+ * Converts the BrowserKit request to a HttpKernel request.
+ *
+ * @param DomRequest $request A Request instance
+ *
+ * @return Request A Request instance
+ */
+ protected function filterRequest(DomRequest $request)
+ {
+ $httpRequest = Request::create($request->getUri(), $request->getMethod(), $request->getParameters(), $request->getCookies(), $request->getFiles(), $request->getServer(), $request->getContent());
+
+ $httpRequest->files->replace($this->filterFiles($httpRequest->files->all()));
+
+ return $httpRequest;
+ }
+
+ /**
+ * Filters an array of files.
+ *
+ * This method created test instances of UploadedFile so that the move()
+ * method can be called on those instances.
+ *
+ * If the size of a file is greater than the allowed size (from php.ini) then
+ * an invalid UploadedFile is returned with an error set to UPLOAD_ERR_INI_SIZE.
+ *
+ * @see Symfony\Component\HttpFoundation\File\UploadedFile
+ *
+ * @param array $files An array of files
+ *
+ * @return array An array with all uploaded files marked as already moved
+ */
+ protected function filterFiles(array $files)
+ {
+ $filtered = array();
+ foreach ($files as $key => $value) {
+ if (is_array($value)) {
+ $filtered[$key] = $this->filterFiles($value);
+ } elseif ($value instanceof UploadedFile) {
+ if ($value->isValid() && $value->getSize() > UploadedFile::getMaxFilesize()) {
+ $filtered[$key] = new UploadedFile(
+ '',
+ $value->getClientOriginalName(),
+ $value->getClientMimeType(),
+ 0,
+ UPLOAD_ERR_INI_SIZE,
+ true
+ );
+ } else {
+ $filtered[$key] = new UploadedFile(
+ $value->getPathname(),
+ $value->getClientOriginalName(),
+ $value->getClientMimeType(),
+ $value->getClientSize(),
+ $value->getError(),
+ true
+ );
+ }
+ } else {
+ $filtered[$key] = $value;
+ }
+ }
+
+ return $filtered;
+ }
+
+ /**
+ * Converts the HttpKernel response to a BrowserKit response.
+ *
+ * @param Response $response A Response instance
+ *
+ * @return Response A Response instance
+ */
+ protected function filterResponse($response)
+ {
+ $headers = $response->headers->all();
+ if ($response->headers->getCookies()) {
+ $cookies = array();
+ foreach ($response->headers->getCookies() as $cookie) {
+ $cookies[] = new DomCookie($cookie->getName(), $cookie->getValue(), $cookie->getExpiresTime(), $cookie->getPath(), $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly());
+ }
+ $headers['Set-Cookie'] = $cookies;
+ }
+
+ return new DomResponse($response->getContent(), $response->getStatusCode(), $headers);
+ }
+}
diff --git a/core/vendor/Symfony/Component/HttpKernel/Config/FileLocator.php b/core/vendor/Symfony/Component/HttpKernel/Config/FileLocator.php
new file mode 100644
index 0000000..6cc615c
--- /dev/null
+++ b/core/vendor/Symfony/Component/HttpKernel/Config/FileLocator.php
@@ -0,0 +1,54 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\Config;
+
+use Symfony\Component\Config\FileLocator as BaseFileLocator;
+use Symfony\Component\HttpKernel\KernelInterface;
+
+/**
+ * FileLocator uses the KernelInterface to locate resources in bundles.
+ *
+ * @author Fabien Potencier
+ */
+class FileLocator extends BaseFileLocator
+{
+ private $kernel;
+ private $path;
+
+ /**
+ * Constructor.
+ *
+ * @param KernelInterface $kernel A KernelInterface instance
+ * @param string $path The path the global resource directory
+ * @param string|array $paths A path or an array of paths where to look for resources
+ */
+ public function __construct(KernelInterface $kernel, $path = null, array $paths = array())
+ {
+ $this->kernel = $kernel;
+ $this->path = $path;
+ $paths[] = $path;
+
+ parent::__construct($paths);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function locate($file, $currentPath = null, $first = true)
+ {
+ if ('@' === $file[0]) {
+ return $this->kernel->locateResource($file, $this->path, $first);
+ }
+
+ return parent::locate($file, $currentPath, $first);
+ }
+}
diff --git a/core/vendor/Symfony/Component/HttpKernel/Controller/ControllerResolver.php b/core/vendor/Symfony/Component/HttpKernel/Controller/ControllerResolver.php
new file mode 100644
index 0000000..d535c55
--- /dev/null
+++ b/core/vendor/Symfony/Component/HttpKernel/Controller/ControllerResolver.php
@@ -0,0 +1,160 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\Controller;
+
+use Symfony\Component\HttpKernel\Log\LoggerInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * ControllerResolver.
+ *
+ * This implementation uses the '_controller' request attribute to determine
+ * the controller to execute and uses the request attributes to determine
+ * the controller method arguments.
+ *
+ * @author Fabien Potencier
+ *
+ * @api
+ */
+class ControllerResolver implements ControllerResolverInterface
+{
+ private $logger;
+
+ /**
+ * Constructor.
+ *
+ * @param LoggerInterface $logger A LoggerInterface instance
+ */
+ public function __construct(LoggerInterface $logger = null)
+ {
+ $this->logger = $logger;
+ }
+
+ /**
+ * Returns the Controller instance associated with a Request.
+ *
+ * This method looks for a '_controller' request attribute that represents
+ * the controller name (a string like ClassName::MethodName).
+ *
+ * @param Request $request A Request instance
+ *
+ * @return mixed|Boolean A PHP callable representing the Controller,
+ * or false if this resolver is not able to determine the controller
+ *
+ * @throws \InvalidArgumentException|\LogicException If the controller can't be found
+ *
+ * @api
+ */
+ public function getController(Request $request)
+ {
+ if (!$controller = $request->attributes->get('_controller')) {
+ if (null !== $this->logger) {
+ $this->logger->warn('Unable to look for the controller as the "_controller" parameter is missing');
+ }
+
+ return false;
+ }
+
+ if (is_array($controller) || (is_object($controller) && method_exists($controller, '__invoke'))) {
+ return $controller;
+ }
+
+ if (false === strpos($controller, ':')) {
+ if (method_exists($controller, '__invoke')) {
+ return new $controller;
+ } elseif (function_exists($controller)) {
+ return $controller;
+ }
+ }
+
+ list($controller, $method) = $this->createController($controller);
+
+ if (!method_exists($controller, $method)) {
+ throw new \InvalidArgumentException(sprintf('Method "%s::%s" does not exist.', get_class($controller), $method));
+ }
+
+ return array($controller, $method);
+ }
+
+ /**
+ * Returns the arguments to pass to the controller.
+ *
+ * @param Request $request A Request instance
+ * @param mixed $controller A PHP callable
+ *
+ * @throws \RuntimeException When value for argument given is not provided
+ *
+ * @api
+ */
+ public function getArguments(Request $request, $controller)
+ {
+ if (is_array($controller)) {
+ $r = new \ReflectionMethod($controller[0], $controller[1]);
+ } elseif (is_object($controller) && !$controller instanceof \Closure) {
+ $r = new \ReflectionObject($controller);
+ $r = $r->getMethod('__invoke');
+ } else {
+ $r = new \ReflectionFunction($controller);
+ }
+
+ return $this->doGetArguments($request, $controller, $r->getParameters());
+ }
+
+ protected function doGetArguments(Request $request, $controller, array $parameters)
+ {
+ $attributes = $request->attributes->all();
+ $arguments = array();
+ foreach ($parameters as $param) {
+ if (array_key_exists($param->getName(), $attributes)) {
+ $arguments[] = $attributes[$param->getName()];
+ } elseif ($param->getClass() && $param->getClass()->isInstance($request)) {
+ $arguments[] = $request;
+ } elseif ($param->isDefaultValueAvailable()) {
+ $arguments[] = $param->getDefaultValue();
+ } else {
+ if (is_array($controller)) {
+ $repr = sprintf('%s::%s()', get_class($controller[0]), $controller[1]);
+ } elseif (is_object($controller)) {
+ $repr = get_class($controller);
+ } else {
+ $repr = $controller;
+ }
+
+ throw new \RuntimeException(sprintf('Controller "%s" requires that you provide a value for the "$%s" argument (because there is no default value or because there is a non optional argument after this one).', $repr, $param->getName()));
+ }
+ }
+
+ return $arguments;
+ }
+
+ /**
+ * Returns a callable for the given controller.
+ *
+ * @param string $controller A Controller string
+ *
+ * @return mixed A PHP callable
+ */
+ protected function createController($controller)
+ {
+ if (false === strpos($controller, '::')) {
+ throw new \InvalidArgumentException(sprintf('Unable to find controller "%s".', $controller));
+ }
+
+ list($class, $method) = explode('::', $controller, 2);
+
+ if (!class_exists($class)) {
+ throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class));
+ }
+
+ return array(new $class(), $method);
+ }
+}
diff --git a/core/vendor/Symfony/Component/HttpKernel/Controller/ControllerResolverInterface.php b/core/vendor/Symfony/Component/HttpKernel/Controller/ControllerResolverInterface.php
new file mode 100644
index 0000000..986a13d
--- /dev/null
+++ b/core/vendor/Symfony/Component/HttpKernel/Controller/ControllerResolverInterface.php
@@ -0,0 +1,63 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\Controller;
+
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * A ControllerResolverInterface implementation knows how to determine the
+ * controller to execute based on a Request object.
+ *
+ * It can also determine the arguments to pass to the Controller.
+ *
+ * A Controller can be any valid PHP callable.
+ *
+ * @author Fabien Potencier
+ *
+ * @api
+ */
+interface ControllerResolverInterface
+{
+ /**
+ * Returns the Controller instance associated with a Request.
+ *
+ * As several resolvers can exist for a single application, a resolver must
+ * return false when it is not able to determine the controller.
+ *
+ * The resolver must only throw an exception when it should be able to load
+ * controller but cannot because of some errors made by the developer.
+ *
+ * @param Request $request A Request instance
+ *
+ * @return mixed|Boolean A PHP callable representing the Controller,
+ * or false if this resolver is not able to determine the controller
+ *
+ * @throws \InvalidArgumentException|\LogicException If the controller can't be found
+ *
+ * @api
+ */
+ function getController(Request $request);
+
+ /**
+ * Returns the arguments to pass to the controller.
+ *
+ * @param Request $request A Request instance
+ * @param mixed $controller A PHP callable
+ *
+ * @return array An array of arguments to pass to the controller
+ *
+ * @throws \RuntimeException When value for argument given is not provided
+ *
+ * @api
+ */
+ function getArguments(Request $request, $controller);
+}
diff --git a/core/vendor/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php b/core/vendor/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php
new file mode 100644
index 0000000..37e93b0
--- /dev/null
+++ b/core/vendor/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php
@@ -0,0 +1,185 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\DataCollector;
+
+use Symfony\Component\HttpKernel\KernelInterface;
+use Symfony\Component\HttpKernel\Kernel;
+use Symfony\Component\HttpKernel\DataCollector\DataCollector;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+
+/**
+ * ConfigDataCollector.
+ *
+ * @author Fabien Potencier
+ */
+class ConfigDataCollector extends DataCollector
+{
+ private $kernel;
+
+ /**
+ * Constructor.
+ *
+ * @param KernelInterface $kernel A KernelInterface instance
+ */
+ public function __construct(KernelInterface $kernel)
+ {
+ $this->kernel = $kernel;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function collect(Request $request, Response $response, \Exception $exception = null)
+ {
+ $this->data = array(
+ 'token' => $response->headers->get('X-Debug-Token'),
+ 'symfony_version' => Kernel::VERSION,
+ 'name' => $this->kernel->getName(),
+ 'env' => $this->kernel->getEnvironment(),
+ 'debug' => $this->kernel->isDebug(),
+ 'php_version' => PHP_VERSION,
+ 'xdebug_enabled' => extension_loaded('xdebug'),
+ 'eaccel_enabled' => extension_loaded('eaccelerator') && ini_get('eaccelerator.enable'),
+ 'apc_enabled' => extension_loaded('apc') && ini_get('apc.enabled'),
+ 'xcache_enabled' => extension_loaded('xcache') && ini_get('xcache.cacher'),
+ 'bundles' => array(),
+ );
+
+ foreach ($this->kernel->getBundles() as $name => $bundle) {
+ $this->data['bundles'][$name] = $bundle->getPath();
+ }
+ }
+
+ /**
+ * Gets the token.
+ *
+ * @return string The token
+ */
+ public function getToken()
+ {
+ return $this->data['token'];
+ }
+
+ /**
+ * Gets the Symfony version.
+ *
+ * @return string The Symfony version
+ */
+ public function getSymfonyVersion()
+ {
+ return $this->data['symfony_version'];
+ }
+
+ /**
+ * Gets the PHP version.
+ *
+ * @return string The PHP version
+ */
+ public function getPhpVersion()
+ {
+ return $this->data['php_version'];
+ }
+
+ /**
+ * Gets the application name.
+ *
+ * @return string The application name
+ */
+ public function getAppName()
+ {
+ return $this->data['name'];
+ }
+
+ /**
+ * Gets the environment.
+ *
+ * @return string The environment
+ */
+ public function getEnv()
+ {
+ return $this->data['env'];
+ }
+
+ /**
+ * Returns true if the debug is enabled.
+ *
+ * @return Boolean true if debug is enabled, false otherwise
+ */
+ public function isDebug()
+ {
+ return $this->data['debug'];
+ }
+
+ /**
+ * Returns true if the XDebug is enabled.
+ *
+ * @return Boolean true if XDebug is enabled, false otherwise
+ */
+ public function hasXDebug()
+ {
+ return $this->data['xdebug_enabled'];
+ }
+
+ /**
+ * Returns true if EAccelerator is enabled.
+ *
+ * @return Boolean true if EAccelerator is enabled, false otherwise
+ */
+ public function hasEAccelerator()
+ {
+ return $this->data['eaccel_enabled'];
+ }
+
+ /**
+ * Returns true if APC is enabled.
+ *
+ * @return Boolean true if APC is enabled, false otherwise
+ */
+ public function hasApc()
+ {
+ return $this->data['apc_enabled'];
+ }
+
+ /**
+ * Returns true if XCache is enabled.
+ *
+ * @return Boolean true if XCache is enabled, false otherwise
+ */
+ public function hasXCache()
+ {
+ return $this->data['xcache_enabled'];
+ }
+
+ /**
+ * Returns true if any accelerator is enabled.
+ *
+ * @return Boolean true if any accelerator is enabled, false otherwise
+ */
+ public function hasAccelerator()
+ {
+ return $this->hasApc() || $this->hasEAccelerator() || $this->hasXCache();
+ }
+
+ public function getBundles()
+ {
+ return $this->data['bundles'];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'config';
+ }
+}
diff --git a/core/vendor/Symfony/Component/HttpKernel/DataCollector/DataCollector.php b/core/vendor/Symfony/Component/HttpKernel/DataCollector/DataCollector.php
new file mode 100644
index 0000000..f1002fb
--- /dev/null
+++ b/core/vendor/Symfony/Component/HttpKernel/DataCollector/DataCollector.php
@@ -0,0 +1,36 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\DataCollector;
+
+use Symfony\Component\HttpKernel\Profiler\Profiler;
+
+/**
+ * DataCollector.
+ *
+ * Children of this class must store the collected data in the data property.
+ *
+ * @author Fabien Potencier
+ */
+abstract class DataCollector implements DataCollectorInterface, \Serializable
+{
+ protected $data;
+
+ public function serialize()
+ {
+ return serialize($this->data);
+ }
+
+ public function unserialize($data)
+ {
+ $this->data = unserialize($data);
+ }
+}
diff --git a/core/vendor/Symfony/Component/HttpKernel/DataCollector/DataCollectorInterface.php b/core/vendor/Symfony/Component/HttpKernel/DataCollector/DataCollectorInterface.php
new file mode 100644
index 0000000..5e0ff7a
--- /dev/null
+++ b/core/vendor/Symfony/Component/HttpKernel/DataCollector/DataCollectorInterface.php
@@ -0,0 +1,46 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\DataCollector;
+
+use Symfony\Component\HttpKernel\Profiler\Profiler;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+
+/**
+ * DataCollectorInterface.
+ *
+ * @author Fabien Potencier
+ *
+ * @api
+ */
+interface DataCollectorInterface
+{
+ /**
+ * Collects data for the given Request and Response.
+ *
+ * @param Request $request A Request instance
+ * @param Response $response A Response instance
+ * @param \Exception $exception An Exception instance
+ *
+ * @api
+ */
+ function collect(Request $request, Response $response, \Exception $exception = null);
+
+ /**
+ * Returns the name of the collector.
+ *
+ * @return string The collector name
+ *
+ * @api
+ */
+ function getName();
+}
diff --git a/core/vendor/Symfony/Component/HttpKernel/DataCollector/EventDataCollector.php b/core/vendor/Symfony/Component/HttpKernel/DataCollector/EventDataCollector.php
new file mode 100644
index 0000000..66f7bf8
--- /dev/null
+++ b/core/vendor/Symfony/Component/HttpKernel/DataCollector/EventDataCollector.php
@@ -0,0 +1,77 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\DataCollector;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\Debug\TraceableEventDispatcherInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+
+/**
+ * EventDataCollector.
+ *
+ * @author Fabien Potencier
+ */
+class EventDataCollector extends DataCollector
+{
+ private $dispatcher;
+
+ public function setEventDispatcher(EventDispatcherInterface $dispatcher)
+ {
+ if ($dispatcher instanceof TraceableEventDispatcherInterface) {
+ $this->dispatcher = $dispatcher;
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function collect(Request $request, Response $response, \Exception $exception = null)
+ {
+ $this->data = array(
+ 'called_listeners' => null !== $this->dispatcher ? $this->dispatcher->getCalledListeners() : array(),
+ 'not_called_listeners' => null !== $this->dispatcher ? $this->dispatcher->getNotCalledListeners() : array(),
+ );
+ }
+
+ /**
+ * Gets the called listeners.
+ *
+ * @return array An array of called listeners
+ *
+ * @see TraceableEventDispatcherInterface
+ */
+ public function getCalledListeners()
+ {
+ return $this->data['called_listeners'];
+ }
+
+ /**
+ * Gets the not called listeners.
+ *
+ * @return array An array of not called listeners
+ *
+ * @see TraceableEventDispatcherInterface
+ */
+ public function getNotCalledListeners()
+ {
+ return $this->data['not_called_listeners'];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'events';
+ }
+}
diff --git a/core/vendor/Symfony/Component/HttpKernel/DataCollector/ExceptionDataCollector.php b/core/vendor/Symfony/Component/HttpKernel/DataCollector/ExceptionDataCollector.php
new file mode 100644
index 0000000..d6808ce
--- /dev/null
+++ b/core/vendor/Symfony/Component/HttpKernel/DataCollector/ExceptionDataCollector.php
@@ -0,0 +1,110 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\DataCollector;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\Exception\FlattenException;
+use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
+
+/**
+ * ExceptionDataCollector.
+ *
+ * @author Fabien Potencier
+ */
+class ExceptionDataCollector extends DataCollector
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function collect(Request $request, Response $response, \Exception $exception = null)
+ {
+ if (null !== $exception) {
+ $flattenException = FlattenException::create($exception);
+ if ($exception instanceof HttpExceptionInterface) {
+ $flattenException->setStatusCode($exception->getStatusCode());
+ }
+
+ $this->data = array(
+ 'exception' => $flattenException,
+ );
+ }
+ }
+
+ /**
+ * Checks if the exception is not null.
+ *
+ * @return Boolean true if the exception is not null, false otherwise
+ */
+ public function hasException()
+ {
+ return isset($this->data['exception']);
+ }
+
+ /**
+ * Gets the exception.
+ *
+ * @return \Exception The exception
+ */
+ public function getException()
+ {
+ return $this->data['exception'];
+ }
+
+ /**
+ * Gets the exception message.
+ *
+ * @return string The exception message
+ */
+ public function getMessage()
+ {
+ return $this->data['exception']->getMessage();
+ }
+
+ /**
+ * Gets the exception code.
+ *
+ * @return integer The exception code
+ */
+ public function getCode()
+ {
+ return $this->data['exception']->getCode();
+ }
+
+ /**
+ * Gets the status code.
+ *
+ * @return integer The status code
+ */
+ public function getStatusCode()
+ {
+ return $this->data['exception']->getStatusCode();
+ }
+
+ /**
+ * Gets the exception trace.
+ *
+ * @return array The exception trace
+ */
+ public function getTrace()
+ {
+ return $this->data['exception']->getTrace();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'exception';
+ }
+}
diff --git a/core/vendor/Symfony/Component/HttpKernel/DataCollector/LoggerDataCollector.php b/core/vendor/Symfony/Component/HttpKernel/DataCollector/LoggerDataCollector.php
new file mode 100644
index 0000000..97f7165
--- /dev/null
+++ b/core/vendor/Symfony/Component/HttpKernel/DataCollector/LoggerDataCollector.php
@@ -0,0 +1,106 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\DataCollector;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
+
+/**
+ * LogDataCollector.
+ *
+ * @author Fabien Potencier
+ */
+class LoggerDataCollector extends DataCollector
+{
+ private $logger;
+
+ public function __construct($logger = null)
+ {
+ if (null !== $logger && $logger instanceof DebugLoggerInterface) {
+ $this->logger = $logger;
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function collect(Request $request, Response $response, \Exception $exception = null)
+ {
+ if (null !== $this->logger) {
+ $this->data = array(
+ 'error_count' => $this->logger->countErrors(),
+ 'logs' => $this->sanitizeLogs($this->logger->getLogs()),
+ );
+ }
+ }
+
+ /**
+ * Gets the called events.
+ *
+ * @return array An array of called events
+ *
+ * @see TraceableEventDispatcherInterface
+ */
+ public function countErrors()
+ {
+ return isset($this->data['error_count']) ? $this->data['error_count'] : 0;
+ }
+
+ /**
+ * Gets the logs.
+ *
+ * @return array An array of logs
+ */
+ public function getLogs()
+ {
+ return isset($this->data['logs']) ? $this->data['logs'] : array();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'logger';
+ }
+
+ private function sanitizeLogs($logs)
+ {
+ foreach ($logs as $i => $log) {
+ $logs[$i]['context'] = $this->sanitizeContext($log['context']);
+ }
+
+ return $logs;
+ }
+
+ private function sanitizeContext($context)
+ {
+ if (is_array($context)) {
+ foreach ($context as $key => $value) {
+ $context[$key] = $this->sanitizeContext($value);
+ }
+
+ return $context;
+ }
+
+ if (is_resource($context)) {
+ return sprintf('Resource(%s)', get_resource_type($context));
+ }
+
+ if (is_object($context)) {
+ return sprintf('Object(%s)', get_class($context));
+ }
+
+ return $context;
+ }
+}
diff --git a/core/vendor/Symfony/Component/HttpKernel/DataCollector/MemoryDataCollector.php b/core/vendor/Symfony/Component/HttpKernel/DataCollector/MemoryDataCollector.php
new file mode 100644
index 0000000..c41ca31
--- /dev/null
+++ b/core/vendor/Symfony/Component/HttpKernel/DataCollector/MemoryDataCollector.php
@@ -0,0 +1,51 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\DataCollector;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+
+/**
+ * MemoryDataCollector.
+ *
+ * @author Fabien Potencier
+ */
+class MemoryDataCollector extends DataCollector
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function collect(Request $request, Response $response, \Exception $exception = null)
+ {
+ $this->data = array(
+ 'memory' => memory_get_peak_usage(true),
+ );
+ }
+
+ /**
+ * Gets the memory.
+ *
+ * @return integer The memory
+ */
+ public function getMemory()
+ {
+ return $this->data['memory'];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'memory';
+ }
+}
diff --git a/core/vendor/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php b/core/vendor/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php
new file mode 100644
index 0000000..54d9fac
--- /dev/null
+++ b/core/vendor/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php
@@ -0,0 +1,187 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\DataCollector;
+
+use Symfony\Component\HttpFoundation\Cookie;
+use Symfony\Component\HttpFoundation\ParameterBag;
+use Symfony\Component\HttpFoundation\HeaderBag;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\ResponseHeaderBag;
+
+/**
+ * RequestDataCollector.
+ *
+ * @author Fabien Potencier
+ */
+class RequestDataCollector extends DataCollector
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function collect(Request $request, Response $response, \Exception $exception = null)
+ {
+ $responseHeaders = $response->headers->all();
+ $cookies = array();
+ foreach ($response->headers->getCookies() as $cookie) {
+ $cookies[] = $this->getCookieHeader($cookie->getName(), $cookie->getValue(), $cookie->getExpiresTime(), $cookie->getPath(), $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly());
+ }
+ if (count($cookies) > 0) {
+ $responseHeaders['Set-Cookie'] = $cookies;
+ }
+
+ $attributes = array();
+ foreach ($request->attributes->all() as $key => $value) {
+ if (is_object($value)) {
+ $attributes[$key] = sprintf('Object(%s)', get_class($value));
+ if (is_callable(array($value, '__toString'))) {
+ $attributes[$key] .= sprintf(' = %s', (string) $value);
+ }
+ } else {
+ $attributes[$key] = $value;
+ }
+ }
+
+ $content = null;
+ try {
+ $content = $request->getContent();
+ } catch (\LogicException $e) {
+ // the user already got the request content as a resource
+ $content = false;
+ }
+
+ $this->data = array(
+ 'format' => $request->getRequestFormat(),
+ 'content' => $content,
+ 'content_type' => $response->headers->get('Content-Type') ? $response->headers->get('Content-Type') : 'text/html',
+ 'status_code' => $response->getStatusCode(),
+ 'request_query' => $request->query->all(),
+ 'request_request' => $request->request->all(),
+ 'request_headers' => $request->headers->all(),
+ 'request_server' => $request->server->all(),
+ 'request_cookies' => $request->cookies->all(),
+ 'request_attributes' => $attributes,
+ 'response_headers' => $responseHeaders,
+ 'session_attributes' => $request->hasSession() ? $request->getSession()->all() : array(),
+ 'path_info' => $request->getPathInfo(),
+ );
+ }
+
+ public function getPathInfo()
+ {
+ return $this->data['path_info'];
+ }
+
+ public function getRequestRequest()
+ {
+ return new ParameterBag($this->data['request_request']);
+ }
+
+ public function getRequestQuery()
+ {
+ return new ParameterBag($this->data['request_query']);
+ }
+
+ public function getRequestHeaders()
+ {
+ return new HeaderBag($this->data['request_headers']);
+ }
+
+ public function getRequestServer()
+ {
+ return new ParameterBag($this->data['request_server']);
+ }
+
+ public function getRequestCookies()
+ {
+ return new ParameterBag($this->data['request_cookies']);
+ }
+
+ public function getRequestAttributes()
+ {
+ return new ParameterBag($this->data['request_attributes']);
+ }
+
+ public function getResponseHeaders()
+ {
+ return new ResponseHeaderBag($this->data['response_headers']);
+ }
+
+ public function getSessionAttributes()
+ {
+ return $this->data['session_attributes'];
+ }
+
+ public function getContent()
+ {
+ return $this->data['content'];
+ }
+
+ public function getContentType()
+ {
+ return $this->data['content_type'];
+ }
+
+ public function getStatusCode()
+ {
+ return $this->data['status_code'];
+ }
+
+ public function getFormat()
+ {
+ return $this->data['format'];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'request';
+ }
+
+ private function getCookieHeader($name, $value, $expires, $path, $domain, $secure, $httponly)
+ {
+ $cookie = sprintf('%s=%s', $name, urlencode($value));
+
+ if (0 !== $expires) {
+ if (is_numeric($expires)) {
+ $expires = (int) $expires;
+ } elseif ($expires instanceof \DateTime) {
+ $expires = $expires->getTimestamp();
+ } else {
+ $expires = strtotime($expires);
+ if (false === $expires || -1 == $expires) {
+ throw new \InvalidArgumentException(sprintf('The "expires" cookie parameter is not valid.', $expires));
+ }
+ }
+
+ $cookie .= '; expires='.substr(\DateTime::createFromFormat('U', $expires, new \DateTimeZone('UTC'))->format('D, d-M-Y H:i:s T'), 0, -5);
+ }
+
+ if ($domain) {
+ $cookie .= '; domain='.$domain;
+ }
+
+ $cookie .= '; path='.$path;
+
+ if ($secure) {
+ $cookie .= '; secure';
+ }
+
+ if ($httponly) {
+ $cookie .= '; httponly';
+ }
+
+ return $cookie;
+ }
+}
diff --git a/core/vendor/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php b/core/vendor/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php
new file mode 100644
index 0000000..bdeb84c
--- /dev/null
+++ b/core/vendor/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php
@@ -0,0 +1,110 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\DataCollector;
+
+use Symfony\Component\HttpKernel\DataCollector\DataCollector;
+use Symfony\Component\HttpKernel\KernelInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+
+/**
+ * TimeDataCollector.
+ *
+ * @author Fabien Potencier
+ */
+class TimeDataCollector extends DataCollector
+{
+ protected $kernel;
+
+ public function __construct(KernelInterface $kernel = null)
+ {
+ $this->kernel = $kernel;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function collect(Request $request, Response $response, \Exception $exception = null)
+ {
+ $this->data = array(
+ 'start_time' => (null !== $this->kernel ? $this->kernel->getStartTime() : $_SERVER['REQUEST_TIME']) * 1000,
+ 'events' => array(),
+ );
+ }
+
+ /**
+ * Sets the request events.
+ *
+ * @param array $events The request events
+ */
+ public function setEvents(array $events)
+ {
+ foreach ($events as $event) {
+ $event->ensureStopped();
+ }
+
+ $this->data['events'] = $events;
+ }
+
+ /**
+ * Gets the request events.
+ *
+ * @return array The request events
+ */
+ public function getEvents()
+ {
+ return $this->data['events'];
+ }
+
+ /**
+ * Gets the request elapsed time.
+ *
+ * @return integer The elapsed time
+ */
+ public function getTotalTime()
+ {
+ $values = array_values($this->data['events']);
+ $lastEvent = $values[count($values) - 1];
+
+ return $lastEvent->getOrigin() + $lastEvent->getEndTime() - $this->data['start_time'];
+ }
+
+ /**
+ * Gets the initialization time.
+ *
+ * This is the time spent until the beginning of the request handling.
+ *
+ * @return integer The elapsed time
+ */
+ public function getInitTime()
+ {
+ return $this->data['events']['section']->getOrigin() - $this->getStartTime();
+ }
+
+ /**
+ * Gets the request time.
+ *
+ * @return integer The time
+ */
+ public function getStartTime()
+ {
+ return $this->data['start_time'];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'time';
+ }
+}
diff --git a/core/vendor/Symfony/Component/HttpKernel/Debug/ErrorHandler.php b/core/vendor/Symfony/Component/HttpKernel/Debug/ErrorHandler.php
new file mode 100644
index 0000000..942e82b
--- /dev/null
+++ b/core/vendor/Symfony/Component/HttpKernel/Debug/ErrorHandler.php
@@ -0,0 +1,70 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\Debug;
+
+/**
+ * ErrorHandler.
+ *
+ * @author Fabien Potencier
+ */
+class ErrorHandler
+{
+ private $levels = array(
+ E_WARNING => 'Warning',
+ E_NOTICE => 'Notice',
+ E_USER_ERROR => 'User Error',
+ E_USER_WARNING => 'User Warning',
+ E_USER_NOTICE => 'User Notice',
+ E_STRICT => 'Runtime Notice',
+ E_RECOVERABLE_ERROR => 'Catchable Fatal Error',
+ );
+
+ private $level;
+
+ /**
+ * Register the error handler.
+ *
+ * @param integer $level The level at which the conversion to Exception is done (null to use the error_reporting() value and 0 to disable)
+ *
+ * @return The registered error handler
+ */
+ static public function register($level = null)
+ {
+ $handler = new static();
+ $handler->setLevel($level);
+
+ set_error_handler(array($handler, 'handle'));
+
+ return $handler;
+ }
+
+ public function setLevel($level)
+ {
+ $this->level = null === $level ? error_reporting() : $level;
+ }
+
+ /**
+ * @throws \ErrorException When error_reporting returns error
+ */
+ public function handle($level, $message, $file, $line, $context)
+ {
+ if (0 === $this->level) {
+ return false;
+ }
+
+ if (error_reporting() & $level && $this->level & $level) {
+ throw new \ErrorException(sprintf('%s: %s in %s line %d', isset($this->levels[$level]) ? $this->levels[$level] : $level, $message, $file, $line));
+ }
+
+ return false;
+ }
+}
diff --git a/core/vendor/Symfony/Component/HttpKernel/Debug/ExceptionHandler.php b/core/vendor/Symfony/Component/HttpKernel/Debug/ExceptionHandler.php
new file mode 100644
index 0000000..a9da249
--- /dev/null
+++ b/core/vendor/Symfony/Component/HttpKernel/Debug/ExceptionHandler.php
@@ -0,0 +1,263 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\Debug;
+
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\Exception\FlattenException;
+
+if (!defined('ENT_SUBSTITUTE')) {
+ define('ENT_SUBSTITUTE', 8);
+}
+
+/**
+ * ExceptionHandler converts an exception to a Response object.
+ *
+ * It is mostly useful in debug mode to replace the default PHP/XDebug
+ * output with something prettier and more useful.
+ *
+ * As this class is mainly used during Kernel boot, where nothing is yet
+ * available, the Response content is always HTML.
+ *
+ * @author Fabien Potencier
+ */
+class ExceptionHandler
+{
+ private $debug;
+ private $charset;
+
+ public function __construct($debug = true, $charset = 'UTF-8')
+ {
+ $this->debug = $debug;
+ $this->charset = $charset;
+ }
+
+ /**
+ * Register the exception handler.
+ *
+ * @return The registered exception handler
+ */
+ static public function register($debug = true)
+ {
+ $handler = new static($debug);
+
+ set_exception_handler(array($handler, 'handle'));
+
+ return $handler;
+ }
+
+ /**
+ * Sends a Response for the given Exception.
+ *
+ * @param \Exception $exception An \Exception instance
+ */
+ public function handle(\Exception $exception)
+ {
+ $this->createResponse($exception)->send();
+ }
+
+ /**
+ * Creates the error Response associated with the given Exception.
+ *
+ * @param \Exception|FlattenException $exception An \Exception instance
+ *
+ * @return Response A Response instance
+ */
+ public function createResponse($exception)
+ {
+ $content = '';
+ $title = '';
+ try {
+ if (!$exception instanceof FlattenException) {
+ $exception = FlattenException::create($exception);
+ }
+
+ switch ($exception->getStatusCode()) {
+ case 404:
+ $title = 'Sorry, the page you are looking for could not be found.';
+ break;
+ default:
+ $title = 'Whoops, looks like something went wrong.';
+ }
+
+ if ($this->debug) {
+ $content = $this->getContent($exception);
+ }
+ } catch (\Exception $e) {
+ // something nasty happened and we cannot throw an exception here anymore
+ if ($this->debug) {
+ $title = sprintf('Exception thrown when handling an exception (%s: %s)', get_class($exception), $exception->getMessage());
+ } else {
+ $title = 'Whoops, looks like something went wrong.';
+ }
+ }
+
+ return new Response($this->decorate($content, $title), $exception->getStatusCode());
+ }
+
+ private function getContent($exception)
+ {
+ $message = nl2br($exception->getMessage());
+ $class = $this->abbrClass($exception->getClass());
+ $count = count($exception->getAllPrevious());
+ $content = '';
+ foreach ($exception->toArray() as $position => $e) {
+ $ind = $count - $position + 1;
+ $total = $count + 1;
+ $class = $this->abbrClass($e['class']);
+ $message = nl2br($e['message']);
+ $content .= sprintf(<<
+ %d/%d %s: %s
+\n";
+ }
+
+ return $content;
+ }
+
+ private function decorate($content, $title)
+ {
+ return <<