diff --git a/core/config/schema/core.entity.schema.yml b/core/config/schema/core.entity.schema.yml index b4adf40..e5db26d 100644 --- a/core/config/schema/core.entity.schema.yml +++ b/core/config/schema/core.entity.schema.yml @@ -137,23 +137,3 @@ entity_form_display.field.string: placeholder: type: label label: 'Placeholder' - -entity_form_display.field.datetime_timestamp: - type: entity_field_form_display_base - label: 'Datetime timestamp display format settings' - mapping: - settings: - type: sequence - label: 'Settings' - sequence: - - type: string - -entity_form_display.field.boolean_checkbox: - type: entity_field_form_display_base - label: 'Boolean checkbox display format settings' - mapping: - settings: - type: sequence - label: 'Settings' - sequence: - - type: string diff --git a/core/lib/Drupal/Core/Block/BlockBase.php b/core/lib/Drupal/Core/Block/BlockBase.php index 7d66cf4..237c1b8 100644 --- a/core/lib/Drupal/Core/Block/BlockBase.php +++ b/core/lib/Drupal/Core/Block/BlockBase.php @@ -562,4 +562,11 @@ protected function contextHandler() { return \Drupal::service('context.handler'); } + /** + * {@inheritdoc} + */ + public function getOperationLinks() { + return array(); + } + } diff --git a/core/lib/Drupal/Core/Block/BlockPluginInterface.php b/core/lib/Drupal/Core/Block/BlockPluginInterface.php index 200d10d..a25486f 100644 --- a/core/lib/Drupal/Core/Block/BlockPluginInterface.php +++ b/core/lib/Drupal/Core/Block/BlockPluginInterface.php @@ -12,6 +12,7 @@ use Drupal\Core\Cache\CacheableInterface; use Drupal\Component\Plugin\PluginInspectionInterface; use Drupal\Component\Plugin\ConfigurablePluginInterface; +use Drupal\Core\Entity\OperationsProviderInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Plugin\PluginFormInterface; use Drupal\Core\Session\AccountInterface; @@ -26,7 +27,7 @@ * * @ingroup block_api */ -interface BlockPluginInterface extends ConfigurablePluginInterface, PluginFormInterface, PluginInspectionInterface, CacheableInterface, DerivativeInspectionInterface { +interface BlockPluginInterface extends ConfigurablePluginInterface, PluginFormInterface, PluginInspectionInterface, CacheableInterface, DerivativeInspectionInterface, OperationsProviderInterface { /** * Returns the user-facing block label. diff --git a/core/lib/Drupal/Core/Datetime/Plugin/Field/FieldWidget/TimestampDatetimeWidget.php b/core/lib/Drupal/Core/Datetime/Plugin/Field/FieldWidget/TimestampDatetimeWidget.php deleted file mode 100644 index 66ac11d..0000000 --- a/core/lib/Drupal/Core/Datetime/Plugin/Field/FieldWidget/TimestampDatetimeWidget.php +++ /dev/null @@ -1,68 +0,0 @@ -getPattern(); - $time_format = DateFormat::load('html_time')->getPattern(); - $default_value = isset($items[$delta]->value) ? DrupalDateTime::createFromTimestamp($items[$delta]->value) : ''; - $element['value'] = $element + array( - '#type' => 'datetime', - '#default_value' => $default_value, - '#date_year_range' => '1902:2037', - ); - $element['value']['#description'] = $this->t('Format: %format. Leave blank to use the time of form submission.', array('%format' => Datetime::formatExample($date_format . ' ' . $time_format))); - - return $element; - } - - /** - * {@inheritdoc} - */ - public function massageFormValues(array $values, array $form, FormStateInterface $form_state) { - foreach ($values as &$item) { - // @todo The structure is different whether access is denied or not, to - // be fixed in https://www.drupal.org/node/2326533. - if (isset($item['value']) && $item['value'] instanceof DrupalDateTime) { - $date = $item['value']; - } - else if (isset($item['value']['object']) && $item['value']['object'] instanceof DrupalDateTime) { - $date = $item['value']['object']; - } - else { - $date = new DrupalDateTime(); - } - $item['value'] = $date->getTimestamp(); - } - return $values; - } - -} diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php index ba7380a..fb62145 100644 --- a/core/lib/Drupal/Core/Entity/Entity.php +++ b/core/lib/Drupal/Core/Entity/Entity.php @@ -547,4 +547,11 @@ public function toArray() { return array(); } + /** + * {@inheritdoc} + */ + public function getOperationLinks() { + return array(); + } + } diff --git a/core/lib/Drupal/Core/Entity/EntityInterface.php b/core/lib/Drupal/Core/Entity/EntityInterface.php index 4399d01..06ef6bd 100644 --- a/core/lib/Drupal/Core/Entity/EntityInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityInterface.php @@ -12,7 +12,7 @@ /** * Defines a common interface for all entity objects. */ -interface EntityInterface extends AccessibleInterface { +interface EntityInterface extends AccessibleInterface, OperationsProviderInterface { /** * Returns the entity UUID (Universally Unique Identifier). diff --git a/core/lib/Drupal/Core/Entity/OperationsProviderInterface.php b/core/lib/Drupal/Core/Entity/OperationsProviderInterface.php new file mode 100644 index 0000000..bc873e0 --- /dev/null +++ b/core/lib/Drupal/Core/Entity/OperationsProviderInterface.php @@ -0,0 +1,23 @@ + $item) { - $elements[$delta] = array('#markup' => format_date($item->value)); - } - - return $elements; - } - -} diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/CreatedItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/CreatedItem.php index 367a1bc..9b2e055 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/CreatedItem.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/CreatedItem.php @@ -14,8 +14,7 @@ * id = "created", * label = @Translation("Created"), * description = @Translation("An entity field containing a UNIX timestamp of when the entity has been created."), - * no_ui = TRUE, - * default_formatter = "timestamp", + * no_ui = TRUE * ) */ class CreatedItem extends TimestampItem { diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/TimestampItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/TimestampItem.php index d355287..ba432e3 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/TimestampItem.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/TimestampItem.php @@ -18,19 +18,7 @@ * id = "timestamp", * label = @Translation("Timestamp"), * description = @Translation("An entity field containing a UNIX timestamp value."), - * no_ui = TRUE, - * default_formatter = "timestamp", - * constraints = { - * "ComplexData" = { - * "value" = { - * "Range" = { - * "min" = "-2147483648", - * "max" = "2147483648", - * } - * } - * } - * } - * ) + * no_ui = TRUE * ) */ class TimestampItem extends FieldItemBase { @@ -57,5 +45,4 @@ public static function schema(FieldStorageDefinitionInterface $field_definition) ), ); } - } diff --git a/core/modules/block/src/BlockListBuilder.php b/core/modules/block/src/BlockListBuilder.php index e5da65d..ffbb46c 100644 --- a/core/modules/block/src/BlockListBuilder.php +++ b/core/modules/block/src/BlockListBuilder.php @@ -383,6 +383,8 @@ public function getDefaultOperations(EntityInterface $entity) { $operations['edit']['title'] = t('Configure'); } + $operations += $entity->getOperationLinks(); + return $operations; } diff --git a/core/modules/block/src/Entity/Block.php b/core/modules/block/src/Entity/Block.php index ee977d0..d09a7fc 100644 --- a/core/modules/block/src/Entity/Block.php +++ b/core/modules/block/src/Entity/Block.php @@ -174,4 +174,13 @@ public function getVisibility() { return $this->getPlugin()->getVisibilityConditions()->getConfiguration(); } + /** + * {@inheritdoc} + */ + public function getOperationLinks() { + $plugin = $this->getPlugin(); + $links = $plugin->getOperationLinks(); + return $links; + } + } diff --git a/core/modules/datetime/datetime.module b/core/modules/datetime/datetime.module index f633164..ffae4f5 100644 --- a/core/modules/datetime/datetime.module +++ b/core/modules/datetime/datetime.module @@ -9,6 +9,9 @@ use Drupal\Core\Datetime\DrupalDateTime; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\Core\Template\Attribute; +use Drupal\Core\Datetime\Element\Datetime; +use Drupal\node\NodeInterface; /** * Defines the timezone that dates should be stored in. @@ -134,3 +137,23 @@ function datetime_datelist_widget_validate(&$element, FormStateInterface $form_s function datetime_date_default_time($date) { $date->setTime(12, 0, 0); } + +/** + * Implements hook_form_BASE_FORM_ID_alter() for node forms. + */ +function datetime_form_node_form_alter(&$form, FormStateInterface $form_state, $form_id) { + // Alter the 'Authored on' date to use datetime. + $form['created']['#type'] = 'datetime'; + $date_format = entity_load('date_format', 'html_date')->getPattern(); + $time_format = entity_load('date_format', 'html_time')->getPattern(); + $form['created']['#description'] = t('Format: %format. Leave blank to use the time of form submission.', array('%format' => Datetime::formatExample($date_format . ' ' . $time_format))); + unset($form['created']['#maxlength']); +} + +/** + * Implements hook_node_prepare_form(). + */ +function datetime_node_prepare_form(NodeInterface $node, $operation, FormStateInterface $form_state) { + // Prepare the 'Authored on' date to use datetime. + $node->date = DrupalDateTime::createFromTimestamp($node->getCreatedTime()); +} diff --git a/core/modules/entity/src/Tests/EntityDisplayTest.php b/core/modules/entity/src/Tests/EntityDisplayTest.php index 2e3657d..6d99ce9 100644 --- a/core/modules/entity/src/Tests/EntityDisplayTest.php +++ b/core/modules/entity/src/Tests/EntityDisplayTest.php @@ -286,23 +286,19 @@ public function testRenameDeleteBundle() { $this->assertEqual('article_rename', $new_form_display->bundle); $this->assertEqual('node.article_rename.default', $new_form_display->id); - $expected_view_dependencies = array( + $expected_dependencies = array( 'entity' => array('field.instance.node.article_rename.body', 'node.type.article_rename'), - 'module' => array('text', 'user') + 'module' => array('text') ); // Check that the display has dependencies on the bundle, fields and the // modules that provide the formatters. $dependencies = $new_display->calculateDependencies(); - $this->assertEqual($expected_view_dependencies, $dependencies); + $this->assertEqual($expected_dependencies, $dependencies); // Check that the form display has dependencies on the bundle, fields and // the modules that provide the formatters. $dependencies = $new_form_display->calculateDependencies(); - $expected_form_dependencies = array( - 'entity' => array('field.instance.node.article_rename.body', 'node.type.article_rename'), - 'module' => array('text') - ); - $this->assertEqual($expected_form_dependencies, $dependencies); + $this->assertEqual($expected_dependencies, $dependencies); // Delete the bundle. $type->delete(); diff --git a/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidget.php b/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidget.php index ef9e6ea..3633b5d 100644 --- a/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidget.php +++ b/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidget.php @@ -73,7 +73,7 @@ public function elementValidate($element, FormStateInterface $form_state, $form) elseif (preg_match("/.+\(([\w.]+)\)/", $element['#value'], $matches)) { $value = $matches[1]; } - if ($value === NULL) { + if (!$value) { // Try to get a match from the input string when the user didn't use the // autocomplete but filled in a value manually. $handler = \Drupal::service('plugin.manager.entity_reference.selection')->getSelectionHandler($this->fieldDefinition); diff --git a/core/modules/entity_reference/src/Tests/EntityReferenceAdminTest.php b/core/modules/entity_reference/src/Tests/EntityReferenceAdminTest.php index 095cdf9..9812800 100644 --- a/core/modules/entity_reference/src/Tests/EntityReferenceAdminTest.php +++ b/core/modules/entity_reference/src/Tests/EntityReferenceAdminTest.php @@ -113,9 +113,6 @@ public function testAvailableFormatters() { // Create entity reference field with taxonomy term as a target. $taxonomy_term_field_name = $this->createEntityReferenceField('taxonomy_term', 'tags'); - // Create entity reference field with user as a target. - $user_field_name = $this->createEntityReferenceField('user'); - // Create entity reference field with node as a target. $node_field_name = $this->createEntityReferenceField('node', $this->type); @@ -135,17 +132,6 @@ public function testAvailableFormatters() { 'hidden', )); - // Test if User Reference Field has the correct formatters. - // Author should be available for this field. - // RSS Category should not be available for this field. - $this->assertFieldSelectOptions('fields[field_' . $user_field_name . '][type]', array( - 'author', - 'entity_reference_entity_id', - 'entity_reference_entity_view', - 'entity_reference_label', - 'hidden', - )); - // Test if Node Entity Reference Field has the correct formatters. // RSS Category should not be available for this field. $this->assertFieldSelectOptions('fields[field_' . $node_field_name . '][type]', array( diff --git a/core/modules/entity_reference/src/Tests/EntityReferenceIntegrationTest.php b/core/modules/entity_reference/src/Tests/EntityReferenceIntegrationTest.php index f13cc5d..c16d1bc 100644 --- a/core/modules/entity_reference/src/Tests/EntityReferenceIntegrationTest.php +++ b/core/modules/entity_reference/src/Tests/EntityReferenceIntegrationTest.php @@ -59,7 +59,6 @@ protected function setUp() { * Tests the entity reference field with all its supported field widgets. */ public function testSupportedEntityTypesAndWidgets() { - $user_id = mt_rand(128, 256); foreach ($this->getTestEntities() as $referenced_entities) { $this->fieldName = 'field_test_' . $referenced_entities[0]->getEntityTypeId(); @@ -69,15 +68,10 @@ public function testSupportedEntityTypesAndWidgets() { // Test the default 'entity_reference_autocomplete' widget. entity_get_form_display($this->entityType, $this->bundle, 'default')->setComponent($this->fieldName)->save(); - $user_id++; - entity_create('user', array( - 'uid' => $user_id, - 'name' => $this->randomString(), - ))->save(); $entity_name = $this->randomMachineName(); $edit = array( 'name' => $entity_name, - 'user_id' => $user_id, + 'user_id' => mt_rand(0, 128), $this->fieldName . '[0][target_id]' => $referenced_entities[0]->label() . ' (' . $referenced_entities[0]->id() . ')', // Test an input of the entity label without a ' (entity_id)' suffix. $this->fieldName . '[1][target_id]' => $referenced_entities[1]->label(), @@ -100,14 +94,9 @@ public function testSupportedEntityTypesAndWidgets() { $target_id = $referenced_entities[0]->label() . ' (' . $referenced_entities[0]->id() . ')'; // Test an input of the entity label without a ' (entity_id)' suffix. $target_id .= ', ' . $referenced_entities[1]->label(); - $user_id++; - entity_create('user', array( - 'uid' => $user_id, - 'name' => $this->randomString(), - ))->save(); $edit = array( 'name' => $entity_name, - 'user_id' => $user_id, + 'user_id' => mt_rand(0, 128), $this->fieldName . '[target_id]' => $target_id, ); $this->drupalPostForm($this->entityType . '/add', $edit, t('Save')); @@ -122,11 +111,9 @@ public function testSupportedEntityTypesAndWidgets() { // Test all the other widgets supported by the entity reference field. // Since we don't know the form structure for these widgets, just test // that editing and saving an already created entity works. - // Also exclude the special author reference widgets. - $exclude = array('entity_reference_autocomplete', 'entity_reference_autocomplete_tags', 'route_based_autocomplete', 'author_autocomplete'); $entity = current(entity_load_multiple_by_properties($this->entityType, array('name' => $entity_name))); $supported_widgets = \Drupal::service('plugin.manager.field.widget')->getOptions('entity_reference'); - $supported_widget_types = array_diff(array_keys($supported_widgets), $exclude); + $supported_widget_types = array_diff(array_keys($supported_widgets), array('entity_reference_autocomplete', 'entity_reference_autocomplete_tags')); foreach ($supported_widget_types as $widget_type) { entity_get_form_display($this->entityType, $this->bundle, 'default')->setComponent($this->fieldName, array( diff --git a/core/modules/forum/config/install/rdf.mapping.node.forum.yml b/core/modules/forum/config/install/rdf.mapping.node.forum.yml index be874cd..7db68c7 100644 --- a/core/modules/forum/config/install/rdf.mapping.node.forum.yml +++ b/core/modules/forum/config/install/rdf.mapping.node.forum.yml @@ -11,12 +11,12 @@ fieldMappings: properties: - 'schema:dateCreated' datatype_callback: - callable: 'Drupal\rdf\CommonDataConverter::dateIso8601Value' + callable: 'date_iso8601' changed: properties: - 'schema:dateModified' datatype_callback: - callable: 'Drupal\rdf\CommonDataConverter::dateIso8601Value' + callable: 'date_iso8601' body: properties: - 'schema:text' diff --git a/core/modules/forum/src/Tests/ForumBlockTest.php b/core/modules/forum/src/Tests/ForumBlockTest.php index 78e1c44..4b4942b 100644 --- a/core/modules/forum/src/Tests/ForumBlockTest.php +++ b/core/modules/forum/src/Tests/ForumBlockTest.php @@ -169,8 +169,8 @@ protected function createForumTopics($count = 5) { 'body[0][value]' => $body, // Forum posts are ordered by timestamp, so force a unique timestamp by // adding the index. - 'created[0][value][date]' => $date->format('Y-m-d'), - 'created[0][value][time]' => $date->format('H:i:s'), + 'created[date]' => $date->format('Y-m-d'), + 'created[time]' => $date->format('H:i:s'), ); // Create the forum topic, preselecting the forum ID via a URL parameter. diff --git a/core/modules/node/node.info.yml b/core/modules/node/node.info.yml index ab8e3c3..e61b363 100644 --- a/core/modules/node/node.info.yml +++ b/core/modules/node/node.info.yml @@ -7,4 +7,3 @@ core: 8.x configure: node.overview_types dependencies: - text - - entity_reference diff --git a/core/modules/node/node.js b/core/modules/node/node.js index 1a82ea1..7e088ef 100644 --- a/core/modules/node/node.js +++ b/core/modules/node/node.js @@ -27,8 +27,8 @@ $context.find('.node-form-author').drupalSetSummary(function (context) { var $context = $(context); - var name = $context.find('.field-name-uid input').val(), - date = $context.find('.field-name-created input').val(); + var name = $context.find('.form-item-name input').val() || drupalSettings.anonymous, + date = $context.find('.form-item-date input').val(); return date ? Drupal.t('By @name on @date', { '@name': name, '@date': date }) : Drupal.t('By @name', { '@name': name }); @@ -39,7 +39,7 @@ var vals = []; if ($context.find('input').is(':checked')) { - $context.find('input:checked').next('label').each(function () { + $context.find('input:checked').parent().each(function () { vals.push(Drupal.checkPlain($.trim($(this).text()))); }); return vals.join(', '); diff --git a/core/modules/node/node.module b/core/modules/node/node.module index 55cc9ce..d8882cc 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -177,14 +177,6 @@ function node_theme() { 'base hook' => 'field', 'template' => 'field--node--title', ), - 'field__node__uid' => array( - 'base hook' => 'field', - 'template' => 'field--node--uid', - ), - 'field__node__created' => array( - 'base hook' => 'field', - 'template' => 'field--node--created', - ), ); } @@ -206,6 +198,15 @@ function node_entity_view_display_alter(EntityViewDisplayInterface $display, $co } /** + * Implements hook_entity_form_display_alter(). + */ +function node_entity_form_display_alter(EntityFormDisplayInterface $form_display, $context) { + if ($context['entity_type'] == 'node') { + $node_type = node_type_load($context['bundle']); + } +} + +/** * Gathers a listing of links to nodes. * * @param $result @@ -613,10 +614,14 @@ function template_preprocess_node(&$variables) { $variables['node'] = $variables['elements']['#node']; /** @var \Drupal\node\NodeInterface $node */ $node = $variables['node']; - $variables['date'] = drupal_render($variables['elements']['created'], TRUE); - unset($variables['elements']['created']); - $variables['author_name'] = drupal_render($variables['elements']['uid'], TRUE); - unset($variables['elements']['uid']); + + $variables['date'] = format_date($node->getCreatedTime()); + $username = array( + '#theme' => 'username', + '#account' => $node->getOwner(), + '#link_options' => array('attributes' => array('rel' => 'author')), + ); + $variables['author_name'] = drupal_render($username); $variables['url'] = $node->url('canonical', array( 'language' => $node->language(), diff --git a/core/modules/node/src/Controller/NodeController.php b/core/modules/node/src/Controller/NodeController.php index 2990324..3382c0b 100644 --- a/core/modules/node/src/Controller/NodeController.php +++ b/core/modules/node/src/Controller/NodeController.php @@ -91,7 +91,11 @@ public function addPage() { * A node submission form. */ public function add(NodeTypeInterface $node_type) { + $account = $this->currentUser(); + $node = $this->entityManager()->getStorage('node')->create(array( + 'uid' => $account->id(), + 'name' => $account->getUsername() ?: '', 'type' => $node_type->type, )); diff --git a/core/modules/node/src/Entity/Node.php b/core/modules/node/src/Entity/Node.php index 03ccd91..e4bbc04 100644 --- a/core/modules/node/src/Entity/Node.php +++ b/core/modules/node/src/Entity/Node.php @@ -372,29 +372,11 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { ->setDisplayConfigurable('form', TRUE); $fields['uid'] = BaseFieldDefinition::create('entity_reference') - ->setLabel(t('Authored by')) - ->setDescription(t('The user ID of the node author.')) + ->setLabel(t('Author')) + ->setDescription(t('The user that is the node author.')) ->setRevisionable(TRUE) ->setSetting('target_type', 'user') - ->setSetting('handler', 'default') - ->setDefaultValueCallback(array('Drupal\node\Entity\Node', 'getCurrentUserId')) - ->setTranslatable(TRUE) - ->setDisplayOptions('view', array( - 'label' => 'hidden', - 'type' => 'author', - 'weight' => 0, - )) - ->setDisplayOptions('form', array( - 'type' => 'entity_reference_autocomplete', - 'weight' => 5, - 'settings' => array( - 'match_operator' => 'CONTAINS', - 'size' => '60', - 'autocomplete_type' => 'tags', - 'placeholder' => '', - ), - )) - ->setDisplayConfigurable('form', TRUE); + ->setTranslatable(TRUE); $fields['status'] = BaseFieldDefinition::create('boolean') ->setLabel(t('Publishing status')) @@ -404,20 +386,10 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { ->setDefaultValue(TRUE); $fields['created'] = BaseFieldDefinition::create('created') - ->setLabel(t('Authored on')) + ->setLabel(t('Created')) ->setDescription(t('The time that the node was created.')) ->setRevisionable(TRUE) - ->setTranslatable(TRUE) - ->setDisplayOptions('view', array( - 'label' => 'hidden', - 'type' => 'timestamp', - 'weight' => 0, - )) - ->setDisplayOptions('form', array( - 'type' => 'datetime_timestamp', - 'weight' => 10, - )) - ->setDisplayConfigurable('form', TRUE); + ->setTranslatable(TRUE); $fields['changed'] = BaseFieldDefinition::create('changed') ->setLabel(t('Changed')) @@ -430,29 +402,13 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { ->setDescription(t('A boolean indicating whether the node should be displayed on the front page.')) ->setRevisionable(TRUE) ->setTranslatable(TRUE) - ->setDefaultValue(TRUE) - ->setDisplayOptions('form', array( - 'type' => 'boolean_checkbox', - 'settings' => array( - 'display_label' => TRUE, - ), - 'weight' => 15, - )) - ->setDisplayConfigurable('form', TRUE); + ->setDefaultValue(TRUE); $fields['sticky'] = BaseFieldDefinition::create('boolean') ->setLabel(t('Sticky')) ->setDescription(t('A boolean indicating whether the node should be displayed at the top of lists in which it appears.')) ->setRevisionable(TRUE) - ->setTranslatable(TRUE) - ->setDisplayOptions('form', array( - 'type' => 'boolean_checkbox', - 'settings' => array( - 'display_label' => TRUE, - ), - 'weight' => 16, - )) - ->setDisplayConfigurable('form', TRUE); + ->setTranslatable(TRUE); $fields['revision_timestamp'] = BaseFieldDefinition::create('created') ->setLabel(t('Revision timestamp')) @@ -469,30 +425,11 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { $fields['revision_log'] = BaseFieldDefinition::create('string_long') ->setLabel(t('Revision log message')) - ->setDescription(t('Briefly describe the changes you have made.')) + ->setDescription(t('The log entry explaining the changes in this revision.')) ->setRevisionable(TRUE) - ->setTranslatable(TRUE) - ->setDisplayOptions('form', array( - 'type' => 'string_textarea', - 'weight' => 25, - 'settings' => array( - 'rows' => 4, - ), - )); + ->setTranslatable(TRUE); return $fields; } - /** - * Default value callback for 'uid' base field definition. - * - * @see ::baseFieldDefinitions() - * - * @return array - * An array of default values. - */ - public static function getCurrentUserId() { - return array(\Drupal::currentUser()->id()); - } - } diff --git a/core/modules/node/src/NodeAccessControlHandler.php b/core/modules/node/src/NodeAccessControlHandler.php index 5deb5c9..8cde33b 100644 --- a/core/modules/node/src/NodeAccessControlHandler.php +++ b/core/modules/node/src/NodeAccessControlHandler.php @@ -129,28 +129,14 @@ protected function checkCreateAccess(AccountInterface $account, array $context, * {@inheritdoc} */ protected function checkFieldAccess($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) { - // Only users with the administer nodes permission can edit administrative - // fields. - $administrative_fields = array('uid', 'status', 'created', 'promote', 'sticky'); + $administrative_fields = array('uid', 'status', 'created', 'promote', 'sticky', 'revision_log'); + $read_only_fields = array('changed', 'revision_timestamp', 'revision_uid'); if ($operation == 'edit' && in_array($field_definition->getName(), $administrative_fields)) { return $account->hasPermission('administer nodes'); } - - // No user can change read only fields. - $read_only_fields = array('changed', 'revision_timestamp', 'revision_uid'); if ($operation == 'edit' && in_array($field_definition->getName(), $read_only_fields)) { return FALSE; } - - // Users have access to the revision_log field either if they have - // administrative permissions or if the new revision option is enabled. - if ($operation == 'edit' && $field_definition->getName() == 'revision_log') { - if ($account->hasPermission('administer nodes')) { - return TRUE; - } - $node_type_settings = $items->getEntity()->type->entity->getModuleSettings('node'); - return !empty($node_type_settings['options']['revision']); - } return parent::checkFieldAccess($operation, $field_definition, $account, $items); } diff --git a/core/modules/node/src/NodeForm.php b/core/modules/node/src/NodeForm.php index 7690b7c..4cf7edd 100644 --- a/core/modules/node/src/NodeForm.php +++ b/core/modules/node/src/NodeForm.php @@ -7,14 +7,15 @@ namespace Drupal\node; -use Drupal\Component\Utility\Html; +use Drupal\Component\Utility\NestedArray; +use Drupal\Core\Datetime\DrupalDateTime; use Drupal\Core\Entity\ContentEntityForm; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Language\LanguageInterface; +use Drupal\Component\Utility\String; use Drupal\Core\Entity\EntityManagerInterface; use Drupal\user\TempStoreFactory; use Symfony\Component\DependencyInjection\ContainerInterface; -use Drupal\user\Entity\User; /** * Form controller for the node edit forms. @@ -64,11 +65,12 @@ public static function create(ContainerInterface $container) { protected function prepareEntity() { /** @var \Drupal\node\NodeInterface $node */ $node = $this->entity; - // Make node type settings easily accessible. - $type = $node->type->entity; + // Set up default values, if required. + $type = entity_load('node_type', $node->bundle()); $this->settings = $type->getModuleSettings('node'); if (!$node->isNew()) { + $node->date = format_date($node->getCreatedTime(), 'custom', 'Y-m-d H:i:s O'); // Remove the revision log message from the original node entity. $node->revision_log = NULL; } @@ -78,8 +80,8 @@ protected function prepareEntity() { * {@inheritdoc} */ public function form(array $form, FormStateInterface $form_state) { - // Try to restore from temp store, this must be done before calling - // parent::form(). + + // Try to restore from temp store. $uuid = $this->entity->uuid(); $store = $this->tempStoreFactory->get('node_preview'); @@ -104,12 +106,13 @@ public function form(array $form, FormStateInterface $form_state) { $form['#title'] = $this->t('Edit @type @title', array('@type' => node_get_type_label($node), '@title' => $node->label())); } - $current_user = $this->currentUser(); + $current_user = \Drupal::currentUser(); + $user_config = \Drupal::config('user.settings'); // Override the default CSS class name, since the user-defined node type // name in 'TYPE-node-form' potentially clashes with third-party class // names. - $form['#attributes']['class'][0] = Html::getClass('node-' . $node->getType() . '-form'); + $form['#attributes']['class'][0] = drupal_html_class('node-' . $node->getType() . '-form'); // Changed must be sent to the client, for later overwrite error checking. $form['changed'] = array( @@ -131,9 +134,8 @@ public function form(array $form, FormStateInterface $form_state) { '#attributes' => array('class' => array('entity-meta')), '#weight' => 99, ); - $form = parent::form($form, $form_state); - // Add a revision_log field if the "Create new revision" option is checked, + // Add a revision log field if the "Create new revision" option is checked, // or if the current user has the ability to check that option. $form['revision_information'] = array( '#type' => 'details', @@ -155,17 +157,23 @@ public function form(array $form, FormStateInterface $form_state) { '#type' => 'checkbox', '#title' => t('Create new revision'), '#default_value' => !empty($this->settings['options']['revision']), - '#access' => $current_user->hasPermission('administer nodes'), + '#access' => $node->isNewRevision() || $current_user->hasPermission('administer nodes'), '#group' => 'revision_information', ); - $form['revision_log'] += array( + $form['revision_log'] = array( + '#type' => 'textarea', + '#title' => t('Revision log message'), + '#rows' => 4, + '#default_value' => !empty($node->revision_log->value) ? $node->revision_log->value : '', + '#description' => t('Briefly describe the changes you have made.'), '#states' => array( 'visible' => array( ':input[name="revision"]' => array('checked' => TRUE), ), ), '#group' => 'revision_information', + '#access' => $node->isNewRevision() || $current_user->hasPermission('administer nodes'), ); // Node author information for administrators. @@ -178,18 +186,37 @@ public function form(array $form, FormStateInterface $form_state) { ), '#attached' => array( 'library' => array('node/drupal.node'), + 'js' => array( + array( + 'type' => 'setting', + 'data' => array('anonymous' => $user_config->get('anonymous')), + ), + ), ), '#weight' => 90, '#optional' => TRUE, ); - if (isset($form['uid'])) { - $form['uid']['#group'] = 'author'; - } - - if (isset($form['created'])) { - $form['created']['#group'] = 'author'; - } + $form['uid'] = array( + '#type' => 'textfield', + '#title' => t('Authored by'), + '#maxlength' => 60, + '#autocomplete_route_name' => 'user.autocomplete', + '#default_value' => $node->getOwnerId()? $node->getOwner()->getUsername() : '', + '#weight' => -1, + '#description' => t('Leave blank for %anonymous.', array('%anonymous' => $user_config->get('anonymous'))), + '#group' => 'author', + '#access' => $current_user->hasPermission('administer nodes'), + ); + $form['created'] = array( + '#type' => 'textfield', + '#title' => t('Authored on'), + '#maxlength' => 25, + '#description' => t('Format: %time. The date format is YYYY-MM-DD and %timezone is the time zone offset from UTC. Leave blank to use the time of form submission.', array('%time' => !empty($node->date) ? date_format(date_create($node->date), 'Y-m-d H:i:s O') : format_date($node->getCreatedTime(), 'custom', 'Y-m-d H:i:s O'), '%timezone' => !empty($node->date) ? date_format(date_create($node->date), 'O') : format_date($node->getCreatedTime(), 'custom', 'O'))), + '#default_value' => !empty($node->date) ? $node->date : '', + '#group' => 'author', + '#access' => $current_user->hasPermission('administer nodes'), + ); // Node options for administrators. $form['options'] = array( @@ -206,15 +233,23 @@ public function form(array $form, FormStateInterface $form_state) { '#optional' => TRUE, ); - if (isset($form['promote'])) { - $form['promote']['#group'] = 'options'; - } + $form['promote'] = array( + '#type' => 'checkbox', + '#title' => t('Promoted to front page'), + '#default_value' => $node->isPromoted(), + '#group' => 'options', + '#access' => $current_user->hasPermission('administer nodes'), + ); - if (isset($form['sticky'])) { - $form['sticky']['#group'] = 'options'; - } + $form['sticky'] = array( + '#type' => 'checkbox', + '#title' => t('Sticky at top of lists'), + '#default_value' => $node->isSticky(), + '#group' => 'options', + '#access' => $current_user->hasPermission('administer nodes'), + ); - return $form; + return parent::form($form, $form_state, $node); } /** @@ -303,6 +338,21 @@ public function validate(array $form, FormStateInterface $form_state) { $form_state->setErrorByName('changed', $this->t('The content on this page has either been modified by another user, or you have already submitted modifications using this form. As a result, your changes cannot be saved.')); } + // Validate the "authored by" field. + if (!$form_state->isValueEmpty('uid') && !user_load_by_name($form_state->getValue('uid'))) { + // The use of empty() is mandatory in the context of usernames + // as the empty string denotes the anonymous user. In case we + // are dealing with an anonymous user we set the user ID to 0. + $form_state->setErrorByName('uid', $this->t('The username %name does not exist.', array('%name' => $form_state->getValue('uid')))); + } + + // Validate the "authored on" field. + // The date element contains the date object. + $date = $node->date instanceof DrupalDateTime ? $node->date : new DrupalDateTime($node->date); + if ($date->hasErrors()) { + $form_state->setErrorByName('date', $this->t('You have to specify a valid date.')); + } + // Invoke hook_node_validate() for validation needed by modules. // Can't use \Drupal::moduleHandler()->invokeAll(), because $form_state must // be receivable by reference. @@ -399,13 +449,19 @@ public function buildEntity(array $form, FormStateInterface $form_state) { $entity = parent::buildEntity($form, $form_state); // A user might assign the node author by entering a user name in the node // form, which we then need to translate to a user ID. - // @todo: Remove it when https://www.drupal.org/node/2322525 is pushed. - if (!empty($form_state->getValue('uid')[0]['target_id']) && $account = User::load($form_state->getValue('uid')[0]['target_id'])) { + if (!$form_state->isValueEmpty('uid') && $account = user_load_by_name($form_state->getValue('uid'))) { $entity->setOwnerId($account->id()); } else { $entity->setOwnerId(0); } + + if (!$form_state->isValueEmpty('created') && $form_state->getValue('created') instanceOf DrupalDateTime) { + $entity->setCreatedTime($form_state->getValue('created')->getTimestamp()); + } + else { + $entity->setCreatedTime(REQUEST_TIME); + } return $entity; } diff --git a/core/modules/node/src/NodeTranslationHandler.php b/core/modules/node/src/NodeTranslationHandler.php index 3692c8b..1b27e84 100644 --- a/core/modules/node/src/NodeTranslationHandler.php +++ b/core/modules/node/src/NodeTranslationHandler.php @@ -81,9 +81,8 @@ public function entityFormEntityBuild($entity_type, EntityInterface $entity, arr $translation['status'] = $form_object->getEntity()->isPublished(); // $form['content_translation']['name'] is the equivalent field // for translation author uid. - $account = $entity->uid->entity; - $translation['name'] = $account ? $account->getUsername() : ''; - $translation['created'] = format_date($entity->created->value, 'custom', 'Y-m-d H:i:s O'); + $translation['name'] = $form_state->getValue('uid'); + $translation['created'] = $form_state->getValue('created'); } parent::entityFormEntityBuild($entity_type, $entity, $form, $form_state); } diff --git a/core/modules/node/src/NodeViewBuilder.php b/core/modules/node/src/NodeViewBuilder.php index 8cf1c04..74c79c7 100644 --- a/core/modules/node/src/NodeViewBuilder.php +++ b/core/modules/node/src/NodeViewBuilder.php @@ -76,6 +76,12 @@ protected function getBuildDefaults(EntityInterface $entity, $view_mode, $langco if (isset($defaults['#cache']) && isset($entity->in_preview)) { unset($defaults['#cache']); } + else { + // The node 'submitted' info is not rendered in a standard way (renderable + // array) so we have to add a cache tag manually. + // @todo Delete this once https://drupal.org/node/2226493 lands. + $defaults['#cache']['tags']['user'][] = $entity->getOwnerId(); + } return $defaults; } diff --git a/core/modules/node/src/Tests/MultiStepNodeFormBasicOptionsTest.php b/core/modules/node/src/Tests/MultiStepNodeFormBasicOptionsTest.php index bbba4e9..33375fa 100644 --- a/core/modules/node/src/Tests/MultiStepNodeFormBasicOptionsTest.php +++ b/core/modules/node/src/Tests/MultiStepNodeFormBasicOptionsTest.php @@ -56,13 +56,13 @@ function testMultiStepNodeFormBasicOptions() { $edit = array( 'title[0][value]' => 'a', - 'promote[value]' => FALSE, - 'sticky[value]' => 1, + 'promote' => FALSE, + 'sticky' => 1, "{$this->field_name}[0][value]" => $this->randomString(32), ); $this->drupalPostForm('node/add/page', $edit, t('Add another item')); - $this->assertNoFieldChecked('edit-promote-value', 'Promote stayed unchecked'); - $this->assertFieldChecked('edit-sticky-value', 'Sticky stayed checked'); + $this->assertNoFieldChecked('edit-promote', 'promote stayed unchecked'); + $this->assertFieldChecked('edit-sticky', 'sticky stayed checked'); } } diff --git a/core/modules/node/src/Tests/NodeCreationTest.php b/core/modules/node/src/Tests/NodeCreationTest.php index a6d22fd..53b32b2 100644 --- a/core/modules/node/src/Tests/NodeCreationTest.php +++ b/core/modules/node/src/Tests/NodeCreationTest.php @@ -57,9 +57,9 @@ function testNodeCreation() { $this->assertTrue($node, 'Node found in database.'); // Verify that pages do not show submitted information by default. + $submitted_by = t('Submitted by !username on !datetime', array('!username' => $this->loggedInUser->getUsername(), '!datetime' => format_date($node->getCreatedTime()))); $this->drupalGet('node/' . $node->id()); - $this->assertNoText($node->getOwner()->getUsername()); - $this->assertNoText(format_date($node->getCreatedTime())); + $this->assertNoText($submitted_by); // Change the node type setting to show submitted by information. $node_type = entity_load('node_type', 'page'); @@ -67,8 +67,7 @@ function testNodeCreation() { $node_type->save(); $this->drupalGet('node/' . $node->id()); - $this->assertText($node->getOwner()->getUsername()); - $this->assertText(format_date($node->getCreatedTime())); + $this->assertText($submitted_by); } /** @@ -150,7 +149,7 @@ public function testAuthorAutocomplete() { $this->drupalGet('node/add/page'); - $result = $this->xpath('//input[@id="edit-uid-0-value" and contains(@data-autocomplete-path, "user/autocomplete")]'); + $result = $this->xpath('//input[@id="edit-uid" and contains(@data-autocomplete-path, "user/autocomplete")]'); $this->assertEqual(count($result), 0, 'No autocompletion without access user profiles.'); $admin_user = $this->drupalCreateUser(array('administer nodes', 'create page content', 'access user profiles')); @@ -158,7 +157,7 @@ public function testAuthorAutocomplete() { $this->drupalGet('node/add/page'); - $result = $this->xpath('//input[@id="edit-uid-0-target-id" and contains(@data-autocomplete-path, "/entity_reference/autocomplete/tags/uid/node/page")]'); + $result = $this->xpath('//input[@id="edit-uid" and contains(@data-autocomplete-path, "user/autocomplete")]'); $this->assertEqual(count($result), 1, 'Ensure that the user does have access to the autocompletion'); } diff --git a/core/modules/node/src/Tests/NodeFieldAccessTest.php b/core/modules/node/src/Tests/NodeFieldAccessTest.php index 44aaeda..a616243 100644 --- a/core/modules/node/src/Tests/NodeFieldAccessTest.php +++ b/core/modules/node/src/Tests/NodeFieldAccessTest.php @@ -8,7 +8,6 @@ use Drupal\Component\Utility\String; use Drupal\node\Entity\Node; -use Drupal\node\Entity\NodeType; use Drupal\system\Tests\Entity\EntityUnitTestBase; /** @@ -36,6 +35,7 @@ class NodeFieldAccessTest extends EntityUnitTestBase { 'sticky', 'created', 'uid', + 'revision_log', ); /** @@ -50,32 +50,6 @@ class NodeFieldAccessTest extends EntityUnitTestBase { */ function testAccessToAdministrativeFields() { - // Create the page node type with revisions disabled. - $page = NodeType::create([ - 'type' => 'page', - 'settings' => array( - 'node' => array( - 'options' => array( - 'revision' => FALSE, - ), - ), - ), - ]); - $page->save(); - - // Create the article node type with revisions disabled. - $article = NodeType::create([ - 'type' => 'article', - 'settings' => array( - 'node' => array( - 'options' => array( - 'revision' => TRUE, - ), - ), - ), - ]); - $article->save(); - // An administrator user. No user exists yet, ensure that the first user // does not have UID 1. $content_admin_user = $this->createUser(array('uid' => 2), array('administer nodes')); @@ -105,7 +79,7 @@ function testAccessToAdministrativeFields() { $node2 = Node::create(array( 'title' => $this->randomMachineName(8), 'uid' => $page_manager_user->id(), - 'type' => 'article', + 'type' => 'page', )); $node3 = Node::create(array( 'title' => $this->randomMachineName(8), @@ -148,18 +122,6 @@ function testAccessToAdministrativeFields() { $this->assertFalse($may_view, String::format('No user is not allowed to edit the field @name.', array('@name' => $field))); } } - - // Check the revision_log field on node 1 which has revisions disabled. - $may_update = $node1->revision_log->access('edit', $content_admin_user); - $this->assertTrue($may_update, 'A user with permission "administer nodes" can edit the revision_log field when revisions are disabled.'); - $may_update = $node1->revision_log->access('edit', $page_creator_user); - $this->assertFalse($may_update, 'A user without permission "administer nodes" can not edit the revision_log field when revisions are disabled.'); - - // Check the revision_log field on node 2 which has revisions enabled. - $may_update = $node2->revision_log->access('edit', $content_admin_user); - $this->assertTrue($may_update, 'A user with permission "administer nodes" can edit the revision_log field when revisions are enabled.'); - $may_update = $node2->revision_log->access('edit', $page_creator_user); - $this->assertTrue($may_update, 'A user without permission "administer nodes" can edit the revision_log field when revisions are enabled.'); } } diff --git a/core/modules/node/src/Tests/NodeTestBase.php b/core/modules/node/src/Tests/NodeTestBase.php index 6758560..cc0f8f8 100644 --- a/core/modules/node/src/Tests/NodeTestBase.php +++ b/core/modules/node/src/Tests/NodeTestBase.php @@ -37,6 +37,7 @@ protected function setUp() { $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page', 'settings' => array( // Set proper default options for the page content type. 'node' => array( + 'options' => array('promote' => FALSE), 'submitted' => FALSE, ), ))); diff --git a/core/modules/node/src/Tests/NodeTranslationUITest.php b/core/modules/node/src/Tests/NodeTranslationUITest.php index 9968cff..59416a3 100644 --- a/core/modules/node/src/Tests/NodeTranslationUITest.php +++ b/core/modules/node/src/Tests/NodeTranslationUITest.php @@ -152,11 +152,11 @@ protected function doTestAuthoringInfo() { 'promote' => (bool) mt_rand(0, 1), ); $edit = array( - 'uid[0][target_id]' => $user->getUsername(), - 'created[0][value][date]' => format_date($values[$langcode]['created'], 'custom', 'Y-m-d'), - 'created[0][value][time]' => format_date($values[$langcode]['created'], 'custom', 'H:i:s'), - 'sticky[value]' => $values[$langcode]['sticky'], - 'promote[value]' => $values[$langcode]['promote'], + 'uid' => $user->getUsername(), + 'created[date]' => format_date($values[$langcode]['created'], 'custom', 'Y-m-d'), + 'created[time]' => format_date($values[$langcode]['created'], 'custom', 'H:i:s'), + 'sticky' => $values[$langcode]['sticky'], + 'promote' => $values[$langcode]['promote'], ); $this->drupalPostForm($path, $edit, $this->getFormSubmitAction($entity, $langcode), array('language' => $languages[$langcode])); } diff --git a/core/modules/node/src/Tests/PageEditTest.php b/core/modules/node/src/Tests/PageEditTest.php index a014c80..5d1bc5f 100644 --- a/core/modules/node/src/Tests/PageEditTest.php +++ b/core/modules/node/src/Tests/PageEditTest.php @@ -108,20 +108,21 @@ function testPageAuthoredBy() { // Try to change the 'authored by' field to an invalid user name. $edit = array( - 'uid[0][target_id]' => 'invalid-name', + 'uid' => 'invalid-name', ); $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and keep published')); - $this->assertRaw(t('There are no entities matching "%name".', array('%name' => 'invalid-name'))); + $this->assertText('The username invalid-name does not exist.'); - // Change the authored by field to the anonymous user (uid 0). - $edit['uid[0][target_id]'] = 'Anonymous (0)'; + // Change the authored by field to an empty string, which should assign + // authorship to the anonymous user (uid 0). + $edit['uid'] = ''; $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and keep published')); $node = node_load($node->id(), TRUE); $this->assertIdentical($node->getOwnerId(), '0', 'Node authored by anonymous user.'); // Change the authored by field to another user's name (that is not // logged in). - $edit['uid[0][target_id]'] = $this->web_user->getUsername(); + $edit['uid'] = $this->web_user->getUsername(); $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and keep published')); $node = node_load($node->id(), TRUE); $this->assertIdentical($node->getOwnerId(), $this->web_user->id(), 'Node authored by normal user.'); @@ -129,6 +130,6 @@ function testPageAuthoredBy() { // Check that normal users cannot change the authored by information. $this->drupalLogin($this->web_user); $this->drupalGet('node/' . $node->id() . '/edit'); - $this->assertNoFieldByName('uid[0][target_id]'); + $this->assertNoFieldByName('uid'); } } diff --git a/core/modules/node/src/Tests/PagePreviewTest.php b/core/modules/node/src/Tests/PagePreviewTest.php index aed67e4..708fc1a 100644 --- a/core/modules/node/src/Tests/PagePreviewTest.php +++ b/core/modules/node/src/Tests/PagePreviewTest.php @@ -8,7 +8,6 @@ namespace Drupal\node\Tests; use Drupal\Core\Language\LanguageInterface; -use Drupal\node\Entity\NodeType; /** * Tests the node entity preview functionality. @@ -203,16 +202,14 @@ function testPagePreviewWithRevisions() { $body_key = 'body[0][value]'; $term_key = $this->field_name; // Force revision on "Basic page" content. - $node_type = NodeType::load('page'); - $node_type->settings['node']['options']['revision'] = TRUE; - $node_type->save(); + $this->container->get('config.factory')->get('node.type.page')->set('settings.node.options', array('status', 'revision'))->save(); // Fill in node creation form and preview node. $edit = array(); $edit[$title_key] = $this->randomMachineName(8); $edit[$body_key] = $this->randomMachineName(16); $edit[$term_key] = $this->term->id(); - $edit['revision_log[0][value]'] = $this->randomString(32); + $edit['revision_log'] = $this->randomMachineName(32); $this->drupalPostForm('node/add/page', $edit, t('Preview')); // Check that the preview is displaying the title, body and term. @@ -228,7 +225,7 @@ function testPagePreviewWithRevisions() { $this->assertFieldByName($term_key, $edit[$term_key], 'Term field displayed.'); // Check that the revision log field has the correct value. - $this->assertFieldByName('revision_log[0][value]', $edit['revision_log[0][value]'], 'Revision log field displayed.'); + $this->assertFieldByName('revision_log', $edit['revision_log'], 'Revision log field displayed.'); } } diff --git a/core/modules/node/templates/field--node--created.html.twig b/core/modules/node/templates/field--node--created.html.twig deleted file mode 100644 index dc474c7..0000000 --- a/core/modules/node/templates/field--node--created.html.twig +++ /dev/null @@ -1,18 +0,0 @@ -{# -/** - * @file - * Default theme implementation for the node created field. - * - * This is an override of field.html.twig for the node created field. See that - * template for documentation about its details and overrides. - * - * Available variables: - * - attributes: HTML attributes for the containing span element. - * - items: List of all the field items. - * - * @see field.html.twig - * - * @ingroup themeable - */ -#} -{{ items }} diff --git a/core/modules/node/templates/field--node--uid.html.twig b/core/modules/node/templates/field--node--uid.html.twig deleted file mode 100644 index 163ed85..0000000 --- a/core/modules/node/templates/field--node--uid.html.twig +++ /dev/null @@ -1,18 +0,0 @@ -{# -/** - * @file - * Default theme implementation for the node user field. - * - * This is an override of field.html.twig for the node user field. See that - * template for documentation about its details and overrides. - * - * Available variables: - * - attributes: HTML attributes for the containing span element. - * - items: List of all the field items. - * - * @see field.html.twig - * - * @ingroup themeable - */ -#} -{{ items }} diff --git a/core/modules/node/templates/node.html.twig b/core/modules/node/templates/node.html.twig index 919403a..a08b064 100644 --- a/core/modules/node/templates/node.html.twig +++ b/core/modules/node/templates/node.html.twig @@ -23,8 +23,10 @@ * - author_picture: The node author user entity, rendered using the "compact" * view mode. * - metadata: Metadata for this node. - * - date: Themed creation date field. - * - author_name: Themed author name field. + * - date: Formatted creation date. Preprocess functions can reformat it by + * calling format_date() with the desired parameters on + * $variables['created']. + * - author_name: Themed username of node author output from theme_username(). * - url: Direct URL of the current node. * - display_submitted: Whether submission information should be displayed. * - attributes: HTML attributes for the containing element. @@ -88,7 +90,7 @@
{{ author_picture }}
diff --git a/core/modules/rdf/rdf.module b/core/modules/rdf/rdf.module index c6c6d1a..0ee6614 100644 --- a/core/modules/rdf/rdf.module +++ b/core/modules/rdf/rdf.module @@ -217,7 +217,7 @@ function rdf_entity_prepare_view($entity_type, array $entities, array $displays) $field_mapping = $mapping->getPreparedFieldMapping($name); if ($field_mapping) { foreach ($entity->get($name) as $item) { - $item->_attributes += rdf_rdfa_attributes($field_mapping, $item->toArray()); + $item->_attributes += rdf_rdfa_attributes($field_mapping, $item->getValue()); } } } @@ -234,7 +234,7 @@ function rdf_comment_storage_load($comments) { // to optimize performance for websites that implement an entity cache. $created_mapping = rdf_get_mapping('comment', $comment->bundle()) ->getPreparedFieldMapping('created'); - $comment->rdf_data['date'] = rdf_rdfa_attributes($created_mapping, $comment->get('created')->first()->toArray()); + $comment->rdf_data['date'] = rdf_rdfa_attributes($created_mapping, $comment->getCreatedTime()); $entity = $comment->getCommentedEntity(); $comment->rdf_data['entity_uri'] = $entity->url(); if ($comment->hasParentComment()) { @@ -305,7 +305,7 @@ function rdf_preprocess_node(&$variables) { // Adds RDFa markup for the date. $created_mapping = $mapping->getPreparedFieldMapping('created'); if (!empty($created_mapping) && $variables['display_submitted']) { - $date_attributes = rdf_rdfa_attributes($created_mapping, $variables['node']->get('created')->first()->toArray()); + $date_attributes = rdf_rdfa_attributes($created_mapping, $variables['node']->getCreatedTime()); $rdf_metadata = array( '#theme' => 'rdf_metadata', '#metadata' => array($date_attributes), diff --git a/core/modules/rdf/src/CommonDataConverter.php b/core/modules/rdf/src/CommonDataConverter.php index af95d37..e27f48b 100644 --- a/core/modules/rdf/src/CommonDataConverter.php +++ b/core/modules/rdf/src/CommonDataConverter.php @@ -20,21 +20,7 @@ class CommonDataConverter { * @return mixed * Returns the data. */ - public static function rawValue($data) { + static function rawValue($data) { return $data; } - - /** - * Converts a date entity field array into an ISO 8601 timestamp string. - * - * @param array $data - * The array containing the 'value' element. - * - * @return string - * Returns the ISO 8601 timestamp. - */ - public static function dateIso8601Value($data) { - return date_iso8601($data['value']); - } - } diff --git a/core/modules/rdf/src/Tests/CommentAttributesTest.php b/core/modules/rdf/src/Tests/CommentAttributesTest.php index 82fd967..601a239 100644 --- a/core/modules/rdf/src/Tests/CommentAttributesTest.php +++ b/core/modules/rdf/src/Tests/CommentAttributesTest.php @@ -72,12 +72,12 @@ protected function setUp() { 'created' => array( 'properties' => array('dc:date', 'dc:created'), 'datatype' => 'xsd:dateTime', - 'datatype_callback' => array('callable' => 'Drupal\rdf\CommonDataConverter::dateIso8601Value'), + 'datatype_callback' => array('callable' => 'date_iso8601'), ), 'changed' => array( 'properties' => array('dc:modified'), 'datatype' => 'xsd:dateTime', - 'datatype_callback' => array('callable' => 'Drupal\rdf\CommonDataConverter::dateIso8601Value'), + 'datatype_callback' => array('callable' => 'date_iso8601'), ), 'comment_body' => array( 'properties' => array('content:encoded'), diff --git a/core/modules/rdf/src/Tests/CrudTest.php b/core/modules/rdf/src/Tests/CrudTest.php index 49c14b7..5460c53 100644 --- a/core/modules/rdf/src/Tests/CrudTest.php +++ b/core/modules/rdf/src/Tests/CrudTest.php @@ -90,7 +90,7 @@ function testFieldMapping() { $mapping = array( 'properties' => array('dc:created'), 'datatype' => 'xsd:dateTime', - 'datatype_callback' => array('callable' => 'Drupal\rdf\CommonDataConverter::dateIso8601Value'), + 'datatype_callback' => array('callable' => 'date_iso8601'), ); rdf_get_mapping($this->entity_type, $this->bundle) ->setFieldMapping($field_name, $mapping) @@ -103,7 +103,7 @@ function testFieldMapping() { $mapping = array( 'properties' => array('dc:date'), 'datatype' => 'foo:bar', - 'datatype_callback' => array('callable' => 'Drupal\rdf\CommonDataConverter::dateIso8601Value'), + 'datatype_callback' => array('callable' => 'date_iso8601'), ); rdf_get_mapping($this->entity_type, $this->bundle) ->setFieldMapping($field_name, $mapping) diff --git a/core/modules/rdf/src/Tests/NodeAttributesTest.php b/core/modules/rdf/src/Tests/NodeAttributesTest.php index 8539b2b..e855cc6 100644 --- a/core/modules/rdf/src/Tests/NodeAttributesTest.php +++ b/core/modules/rdf/src/Tests/NodeAttributesTest.php @@ -36,7 +36,7 @@ protected function setUp() { ->setFieldMapping('created', array( 'properties' => array('dc:date', 'dc:created'), 'datatype' => 'xsd:dateTime', - 'datatype_callback' => array('callable' => 'Drupal\rdf\CommonDataConverter::dateIso8601Value'), + 'datatype_callback' => array('callable' => 'date_iso8601'), )) ->save(); } diff --git a/core/modules/system/src/Plugin/Block/SystemMenuBlock.php b/core/modules/system/src/Plugin/Block/SystemMenuBlock.php index dd4c6ad..748a4f5 100644 --- a/core/modules/system/src/Plugin/Block/SystemMenuBlock.php +++ b/core/modules/system/src/Plugin/Block/SystemMenuBlock.php @@ -12,6 +12,8 @@ use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\Menu\MenuActiveTrailInterface; use Drupal\Core\Menu\MenuLinkTreeInterface; +use Drupal\Core\Session\AccountInterface; +use Drupal\Core\Url; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -134,4 +136,22 @@ protected function getRequiredCacheContexts() { return array('cache_context.user.roles', 'cache_context.language'); } + /** + * {@inheritdoc} + */ + public function getOperationLinks() { + $menu = $this->getDerivativeId(); + + $links = array(); + $links['menu-edit'] = array( + 'title' => $this->t('Edit menu'), + 'route_name' => 'entity.menu.edit_form', + 'route_parameters' => array( + 'menu' => $menu, + ), + 'weight' => 50, + ); + return $links; + } + } diff --git a/core/modules/system/src/Tests/Block/SystemMenuBlockTest.php b/core/modules/system/src/Tests/Block/SystemMenuBlockTest.php index 80c3d3d..5df82d6 100644 --- a/core/modules/system/src/Tests/Block/SystemMenuBlockTest.php +++ b/core/modules/system/src/Tests/Block/SystemMenuBlockTest.php @@ -6,6 +6,8 @@ namespace Drupal\system\Tests\Block; use Drupal\simpletest\DrupalUnitTestBase; +use Drupal\user\Entity\Role; +use Drupal\user\Entity\User; /** * Tests \Drupal\system\Plugin\Block\SystemMenuBlock. @@ -24,7 +26,24 @@ class SystemMenuBlockTest extends DrupalUnitTestBase { * * @var array */ - public static $modules = array('system', 'block'); + public static $modules = array('system', 'block', 'user'); + + protected function setUp() { + parent::setUp(); + $this->installEntitySchema('user'); + $user = User::create(array( + 'name' => 'tony', + 'mail' => 'tony@magicalponies.com', + )); + $role = Role::create(array( + 'label' => 'Menu manager', + 'id' => 'menu_manager', + )); + $role->grantPermission('administer menu'); + $role->save(); + $user->addRole($role->id()); + \Drupal::service('current_user')->setAccount($user); + } /** * Tests calculation of a system menu block's configuration dependencies. @@ -61,5 +80,14 @@ public function testSystemMenuBlockConfigDependencies() { ), ); $this->assertIdentical($expected, $dependencies); + + $links = $block->getOperationLinks(); + $menu_link = array( + 'title' => 'Edit menu', + 'route_name' => 'entity.menu.edit_form', + 'route_parameters' => array('menu' => $menu_name), + 'weight' => 50, + ); + $this->assertIdentical($links, ['menu-edit' => $menu_link]); } } diff --git a/core/modules/system/src/Tests/Entity/EntityTranslationFormTest.php b/core/modules/system/src/Tests/Entity/EntityTranslationFormTest.php index 32a154d..844726a 100644 --- a/core/modules/system/src/Tests/Entity/EntityTranslationFormTest.php +++ b/core/modules/system/src/Tests/Entity/EntityTranslationFormTest.php @@ -58,24 +58,24 @@ function testEntityFormLanguage() { $edit = array(); $edit['title[0][value]'] = $this->randomMachineName(8); $edit['body[0][value]'] = $this->randomMachineName(16); + $this->drupalGet('node/add/page'); - $form_langcode = \Drupal::state()->get('entity_test.form_langcode'); + $form_langcode = \Drupal::state()->get('entity_test.form_langcode') ?: FALSE; $this->drupalPostForm(NULL, $edit, t('Save')); $node = $this->drupalGetNodeByTitle($edit['title[0][value]']); - $this->assertTrue($node->language()->id == $form_langcode, 'Form language is the same as the entity language.'); // Edit the node and test the form language. $this->drupalGet($this->langcodes[0] . '/node/' . $node->id() . '/edit'); - $form_langcode = \Drupal::state()->get('entity_test.form_langcode'); + $form_langcode = \Drupal::state()->get('entity_test.form_langcode') ?: FALSE; $this->assertTrue($node->language()->id == $form_langcode, 'Form language is the same as the entity language.'); // Explicitly set form langcode. $langcode = $this->langcodes[0]; $form_state['langcode'] = $langcode; \Drupal::service('entity.form_builder')->getForm($node, 'default', $form_state); - $form_langcode = \Drupal::state()->get('entity_test.form_langcode'); + $form_langcode = \Drupal::state()->get('entity_test.form_langcode') ?: FALSE; $this->assertTrue($langcode == $form_langcode, 'Form language is the same as the language parameter.'); // Enable language selector. @@ -109,7 +109,7 @@ function testEntityFormLanguage() { $node->getTranslation($langcode2)->body->value = $this->randomMachineName(16); $node->save(); $this->drupalGet($langcode2 . '/node/' . $node->id() . '/edit'); - $form_langcode = \Drupal::state()->get('entity_test.form_langcode'); + $form_langcode = \Drupal::state()->get('entity_test.form_langcode') ?: FALSE; $this->assertTrue($langcode2 == $form_langcode, "Node edit form language is $langcode2."); } } diff --git a/core/modules/taxonomy/src/Tests/LegacyTest.php b/core/modules/taxonomy/src/Tests/LegacyTest.php index 0d8bea9..8a2ac68 100644 --- a/core/modules/taxonomy/src/Tests/LegacyTest.php +++ b/core/modules/taxonomy/src/Tests/LegacyTest.php @@ -74,8 +74,8 @@ function testTaxonomyLegacyNode() { $date = new DrupalDateTime('1969-01-01 00:00:00'); $edit = array(); $edit['title[0][value]'] = $this->randomMachineName(); - $edit['created[0][value][date]'] = $date->format('Y-m-d'); - $edit['created[0][value][time]'] = $date->format('H:i:s'); + $edit['created[date]'] = $date->format('Y-m-d'); + $edit['created[time]'] = $date->format('H:i:s'); $edit['body[0][value]'] = $this->randomMachineName(); $edit['field_tags'] = $this->randomMachineName(); $this->drupalPostForm('node/add/article', $edit, t('Save and publish')); diff --git a/core/modules/user/src/Plugin/Field/FieldFormatter/AuthorFormatter.php b/core/modules/user/src/Plugin/Field/FieldFormatter/AuthorFormatter.php deleted file mode 100644 index e30a0bf..0000000 --- a/core/modules/user/src/Plugin/Field/FieldFormatter/AuthorFormatter.php +++ /dev/null @@ -1,58 +0,0 @@ - $item) { - /** @var $referenced_user \Drupal\user\UserInterface */ - if ($referenced_user = $item->entity) { - $elements[$delta] = array( - '#theme' => 'username', - '#account' => $referenced_user, - '#link_options' => array('attributes' => array('rel' => 'author')), - '#cache' => array( - 'tags' => $referenced_user->getCacheTag(), - ), - ); - } - } - - return $elements; - } - - /** - * {@inheritdoc} - */ - public static function isApplicable(FieldDefinitionInterface $field_definition) { - return $field_definition->getFieldStorageDefinition()->getSetting('target_type') == 'user'; - } - -} diff --git a/core/modules/views_ui/src/ViewUI.php b/core/modules/views_ui/src/ViewUI.php index 51e16b2..f29ae6d 100644 --- a/core/modules/views_ui/src/ViewUI.php +++ b/core/modules/views_ui/src/ViewUI.php @@ -1125,4 +1125,11 @@ public function getListCacheTags() { $this->storage->getListCacheTags(); } + /** + * {@inheritdoc} + */ + public function getOperationLinks() { + return $this->storage->getOperationLinks(); + } + } diff --git a/core/profiles/standard/config/install/rdf.mapping.comment.node__comment.yml b/core/profiles/standard/config/install/rdf.mapping.comment.node__comment.yml index d8aa944..00abf0c 100644 --- a/core/profiles/standard/config/install/rdf.mapping.comment.node__comment.yml +++ b/core/profiles/standard/config/install/rdf.mapping.comment.node__comment.yml @@ -11,12 +11,12 @@ fieldMappings: properties: - 'schema:dateCreated' datatype_callback: - callable: 'Drupal\rdf\CommonDataConverter::dateIso8601Value' + callable: 'date_iso8601' changed: properties: - 'schema:dateModified' datatype_callback: - callable: 'Drupal\rdf\CommonDataConverter::dateIso8601Value' + callable: 'date_iso8601' comment_body: properties: - 'schema:text' diff --git a/core/profiles/standard/config/install/rdf.mapping.node.article.yml b/core/profiles/standard/config/install/rdf.mapping.node.article.yml index d1b7f80..10147e7 100644 --- a/core/profiles/standard/config/install/rdf.mapping.node.article.yml +++ b/core/profiles/standard/config/install/rdf.mapping.node.article.yml @@ -11,12 +11,12 @@ fieldMappings: properties: - 'schema:dateCreated' datatype_callback: - callable: 'Drupal\rdf\CommonDataConverter::dateIso8601Value' + callable: 'date_iso8601' changed: properties: - 'schema:dateModified' datatype_callback: - callable: 'Drupal\rdf\CommonDataConverter::dateIso8601Value' + callable: 'date_iso8601' body: properties: - 'schema:text' diff --git a/core/profiles/standard/config/install/rdf.mapping.node.page.yml b/core/profiles/standard/config/install/rdf.mapping.node.page.yml index 38120ff..8a5d377 100644 --- a/core/profiles/standard/config/install/rdf.mapping.node.page.yml +++ b/core/profiles/standard/config/install/rdf.mapping.node.page.yml @@ -11,12 +11,12 @@ fieldMappings: properties: - 'schema:dateCreated' datatype_callback: - callable: 'Drupal\rdf\CommonDataConverter::dateIso8601Value' + callable: 'date_iso8601' changed: properties: - 'schema:dateModified' datatype_callback: - callable: 'Drupal\rdf\CommonDataConverter::dateIso8601Value' + callable: 'date_iso8601' body: properties: - 'schema:text' diff --git a/core/themes/bartik/templates/node.html.twig b/core/themes/bartik/templates/node.html.twig index 745b953..d45b0f0 100644 --- a/core/themes/bartik/templates/node.html.twig +++ b/core/themes/bartik/templates/node.html.twig @@ -23,8 +23,10 @@ * - author_picture: The node author user entity, rendered using the "compact" * view mode. * - metadata: Metadata for this node. - * - date: Themed creation date field. - * - author_name: Themed author name field. + * - date: Formatted creation date. Preprocess functions can reformat it by + * calling format_date() with the desired parameters on + * $variables['created']. + * - author_name: Themed username of node author output from theme_username(). * - url: Direct URL of the current node. * - display_submitted: Whether submission information should be displayed. * - attributes: HTML attributes for the containing element. @@ -84,7 +86,7 @@
{{ author_picture }} - {% trans %}Submitted by {{ author_name|passthrough }} on {{ date|passthrough }}{% endtrans %} + {% trans %}Submitted by {{ author_name|passthrough }} on {{ date }}{% endtrans %} {{ metadata }}