upgrades core to 8.4.2

This commit is contained in:
Bachir Soussi Chiadmi
2017-11-14 16:09:54 +01:00
parent bd60eff9b3
commit c2b4e25be4
3504 changed files with 140306 additions and 38684 deletions
+25
View File
@@ -0,0 +1,25 @@
/**
* @file
* Attaches behaviors for the Path module.
*/
(function ($, Drupal) {
/**
* Behaviors for settings summaries on path edit forms.
*
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
* Attaches summary behavior on path edit forms.
*/
Drupal.behaviors.pathDetailsSummaries = {
attach(context) {
$(context).find('.path-form').drupalSetSummary((context) => {
const path = $('.js-form-item-path-0-alias input').val();
return path ?
Drupal.t('Alias: @alias', { '@alias': path }) :
Drupal.t('No alias');
});
},
};
}(jQuery, Drupal));
+3 -3
View File
@@ -6,8 +6,8 @@ package: Core
# core: 8.x
configure: path.admin_overview
# Information added by Drupal.org packaging script on 2017-08-16
version: '8.3.7'
# Information added by Drupal.org packaging script on 2017-11-03
version: '8.4.2'
core: '8.x'
project: 'drupal'
datestamp: 1502903957
datestamp: 1509719929
+9 -20
View File
@@ -1,29 +1,18 @@
/**
* @file
* Attaches behaviors for the Path module.
*/
* DO NOT EDIT THIS FILE.
* See the following change record for more information,
* https://www.drupal.org/node/2815083
* @preserve
**/
(function ($, Drupal) {
'use strict';
/**
* Behaviors for settings summaries on path edit forms.
*
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
* Attaches summary behavior on path edit forms.
*/
Drupal.behaviors.pathDetailsSummaries = {
attach: function (context) {
attach: function attach(context) {
$(context).find('.path-form').drupalSetSummary(function (context) {
var path = $('.js-form-item-path-0-alias input').val();
return path ?
Drupal.t('Alias: @alias', {'@alias': path}) :
Drupal.t('No alias');
return path ? Drupal.t('Alias: @alias', { '@alias': path }) : Drupal.t('No alias');
});
}
};
})(jQuery, Drupal);
})(jQuery, Drupal);
+16 -1
View File
@@ -5,6 +5,7 @@
* Enables users to rename URLs.
*/
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Form\FormStateInterface;
@@ -62,7 +63,7 @@ function path_form_node_form_alter(&$form, FormStateInterface $form_state) {
* Implements hook_entity_base_field_info().
*/
function path_entity_base_field_info(EntityTypeInterface $entity_type) {
if ($entity_type->id() === 'taxonomy_term' || $entity_type->id() === 'node') {
if (in_array($entity_type->id(), ['taxonomy_term', 'node', 'media'], TRUE)) {
$fields['path'] = BaseFieldDefinition::create('path')
->setLabel(t('URL alias'))
->setTranslatable(TRUE)
@@ -76,3 +77,17 @@ function path_entity_base_field_info(EntityTypeInterface $entity_type) {
return $fields;
}
}
/**
* Implements hook_entity_translation_create().
*/
function path_entity_translation_create(ContentEntityInterface $translation) {
foreach ($translation->getFieldDefinitions() as $field_name => $field_definition) {
if ($field_definition->getType() === 'path' && $translation->get($field_name)->pid) {
// If there are values and a path ID, update the langcode and unset the
// path ID to save this as a new alias.
$translation->get($field_name)->langcode = $translation->language()->getId();
$translation->get($field_name)->pid = NULL;
}
}
}
+2 -2
View File
@@ -16,14 +16,14 @@ class DeleteForm extends ConfirmFormBase {
/**
* The alias storage service.
*
* @var AliasStorageInterface $path
* @var AliasStorageInterface
*/
protected $aliasStorage;
/**
* The path alias being deleted.
*
* @var array $pathAlias
* @var array
*/
protected $pathAlias;
@@ -34,4 +34,42 @@ class PathFieldItemList extends FieldItemList {
\Drupal::service('path.alias_storage')->delete($conditions);
}
/**
* {@inheritdoc}
*/
public function getValue($include_computed = FALSE) {
$this->ensureLoaded();
return parent::getValue($include_computed);
}
/**
* {@inheritdoc}
*/
public function isEmpty() {
$this->ensureLoaded();
return parent::isEmpty();
}
/**
* {@inheritdoc}
*/
public function getIterator() {
$this->ensureLoaded();
return parent::getIterator();
}
/**
* Automatically create the first item for computed fields.
*
* This ensures that ::getValue() and ::isEmpty() calls will behave like a
* non-computed field.
*
* @todo: Move this to the base class in https://www.drupal.org/node/2392845.
*/
protected function ensureLoaded() {
if (!isset($this->list[0]) && $this->definition->isComputed()) {
$this->list[0] = $this->createItem(0);
}
}
}
@@ -17,11 +17,26 @@ use Drupal\Core\TypedData\DataDefinition;
* description = @Translation("An entity field containing a path alias and related data."),
* no_ui = TRUE,
* default_widget = "path",
* list_class = "\Drupal\path\Plugin\Field\FieldType\PathFieldItemList"
* list_class = "\Drupal\path\Plugin\Field\FieldType\PathFieldItemList",
* constraints = {"PathAlias" = {}},
* )
*/
class PathItem extends FieldItemBase {
/**
* Whether the alias has been loaded from the alias storage service yet.
*
* @var bool
*/
protected $isLoaded = FALSE;
/**
* Whether the alias is currently being set.
*
* @var bool
*/
protected $isLoading = FALSE;
/**
* {@inheritdoc}
*/
@@ -30,9 +45,19 @@ class PathItem extends FieldItemBase {
->setLabel(t('Path alias'));
$properties['pid'] = DataDefinition::create('integer')
->setLabel(t('Path id'));
$properties['langcode'] = DataDefinition::create('string')
->setLabel(t('Language Code'));
return $properties;
}
/**
* {@inheritdoc}
*/
public function __get($name) {
$this->ensureLoaded();
return parent::__get($name);
}
/**
* {@inheritdoc}
*/
@@ -40,6 +65,30 @@ class PathItem extends FieldItemBase {
return [];
}
/**
* {@inheritdoc}
*/
public function getValue() {
$this->ensureLoaded();
return parent::getValue();
}
/**
* {@inheritdoc}
*/
public function isEmpty() {
$this->ensureLoaded();
return parent::isEmpty();
}
/**
* {@inheritdoc}
*/
public function getIterator() {
$this->ensureLoaded();
return parent::getIterator();
}
/**
* {@inheritdoc}
*/
@@ -47,6 +96,47 @@ class PathItem extends FieldItemBase {
$this->alias = trim($this->alias);
}
/**
* {@inheritdoc}
*/
public function __set($name, $value) {
// Also ensure that existing values are loaded when setting a value, this
// ensures that it is possible to set a new value immediately after loading
// an entity.
$this->ensureLoaded();
parent::__set($name, $value);
}
/**
* {@inheritdoc}
*/
public function set($property_name, $value, $notify = TRUE) {
// Also ensure that existing values are loaded when setting a value, this
// ensures that it is possible to set a new value immediately after loading
// an entity.
$this->ensureLoaded();
return parent::set($property_name, $value, $notify);
}
/**
* {@inheritdoc}
*/
public function get($property_name) {
$this->ensureLoaded();
return parent::get($property_name);
}
/**
* {@inheritdoc}
*/
public function setValue($values, $notify = TRUE) {
// Also ensure that existing values are loaded when setting a value, this
// ensures that it is possible to set a new value immediately after loading
// an entity.
$this->ensureLoaded();
return parent::setValue($values, $notify);
}
/**
* {@inheritdoc}
*/
@@ -88,4 +178,42 @@ class PathItem extends FieldItemBase {
return 'alias';
}
/**
* Ensures the alias properties are loaded if available.
*
* This ensures that the properties will always be loaded and act like
* non-computed fields when calling ::__get() and getValue().
*
* @todo: Determine if this should be moved to the base class in
* https://www.drupal.org/node/2392845.
*/
protected function ensureLoaded() {
// Make sure to avoid a infinite loop if setValue() has be called from this
// block which calls ensureLoaded().
if (!$this->isLoaded && !$this->isLoading) {
$entity = $this->getEntity();
if (!$entity->isNew()) {
// @todo Support loading languge neutral aliases in
// https://www.drupal.org/node/2511968.
$alias = \Drupal::service('path.alias_storage')->load([
'source' => '/' . $entity->toUrl()->getInternalPath(),
'langcode' => $this->getLangcode(),
]);
if ($alias) {
$this->isLoading = TRUE;
$this->setValue($alias);
$this->isLoading = FALSE;
}
else {
// If there is no existing alias, default the langcode to the current
// language.
// @todo Set the langcode to not specified for untranslatable fields
// in https://www.drupal.org/node/2689459.
$this->langcode = $this->getLangcode();
}
}
$this->isLoaded = TRUE;
}
}
}
@@ -5,7 +5,6 @@ namespace Drupal\path\Plugin\Field\FieldWidget;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
use Symfony\Component\Validator\ConstraintViolationInterface;
/**
@@ -26,23 +25,6 @@ class PathWidget extends WidgetBase {
*/
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
$entity = $items->getEntity();
$path = [];
if (!$entity->isNew()) {
$conditions = ['source' => '/' . $entity->urlInfo()->getInternalPath()];
if ($items->getLangcode() != LanguageInterface::LANGCODE_NOT_SPECIFIED) {
$conditions['langcode'] = $items->getLangcode();
}
$path = \Drupal::service('path.alias_storage')->load($conditions);
if ($path === FALSE) {
$path = [];
}
}
$path += [
'pid' => NULL,
'source' => !$entity->isNew() ? '/' . $entity->urlInfo()->getInternalPath() : NULL,
'alias' => '',
'langcode' => $items->getLangcode(),
];
$element += [
'#element_validate' => [[get_class($this), 'validateFormElement']],
@@ -50,22 +32,22 @@ class PathWidget extends WidgetBase {
$element['alias'] = [
'#type' => 'textfield',
'#title' => $element['#title'],
'#default_value' => $path['alias'],
'#default_value' => $items[$delta]->alias,
'#required' => $element['#required'],
'#maxlength' => 255,
'#description' => $this->t('Specify an alternative path by which this data can be accessed. For example, type "/about" when writing an about page.'),
];
$element['pid'] = [
'#type' => 'value',
'#value' => $path['pid'],
'#value' => $items[$delta]->pid,
];
$element['source'] = [
'#type' => 'value',
'#value' => $path['source'],
];
'#value' => !$entity->isNew() ? '/' . $entity->toUrl()->getInternalPath() : NULL,
];
$element['langcode'] = [
'#type' => 'value',
'#value' => $path['langcode'],
'#value' => $items[$delta]->langcode,
];
return $element;
}
@@ -0,0 +1,19 @@
<?php
namespace Drupal\path\Plugin\Validation\Constraint;
use Symfony\Component\Validator\Constraint;
/**
* Validation constraint for changing path aliases in pending revisions.
*
* @Constraint(
* id = "PathAlias",
* label = @Translation("Path alias.", context = "Validation"),
* )
*/
class PathAliasConstraint extends Constraint {
public $message = 'You can only change the URL alias for the <em>published</em> version of this content.';
}
@@ -0,0 +1,57 @@
<?php
namespace Drupal\path\Plugin\Validation\Constraint;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
/**
* Constraint validator for changing path aliases in pending revisions.
*/
class PathAliasConstraintValidator extends ConstraintValidator implements ContainerInjectionInterface {
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
private $entityTypeManager;
/**
* Creates a new PathAliasConstraintValidator instance.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager) {
$this->entityTypeManager = $entity_type_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity_type.manager')
);
}
/**
* {@inheritdoc}
*/
public function validate($value, Constraint $constraint) {
$entity = !empty($value->getParent()) ? $value->getEntity() : NULL;
if ($entity && !$entity->isNew() && !$entity->isDefaultRevision()) {
/** @var \Drupal\Core\Entity\ContentEntityInterface $original */
$original = $this->entityTypeManager->getStorage($entity->getEntityTypeId())->loadUnchanged($entity->id());
if ($value->alias != $original->path->alias) {
$this->context->addViolation($constraint->message);
}
}
}
}
@@ -19,7 +19,7 @@ class UrlAlias extends DestinationBase implements ContainerFactoryPluginInterfac
/**
* The alias storage service.
*
* @var \Drupal\Core\Path\AliasStorage $aliasStorage
* @var \Drupal\Core\Path\AliasStorage
*/
protected $aliasStorage;
@@ -9,7 +9,7 @@ use Drupal\path\Plugin\migrate\source\UrlAliasBase;
*
* @MigrateSource(
* id = "d6_url_alias",
* source_provider = "path"
* source_module = "path"
* )
*/
class UrlAlias extends UrlAliasBase {
@@ -9,7 +9,7 @@ use Drupal\path\Plugin\migrate\source\UrlAliasBase;
*
* @MigrateSource(
* id = "d7_url_alias",
* source_provider = "path"
* source_module = "path"
* )
*/
class UrlAlias extends UrlAliasBase {
@@ -92,7 +92,8 @@ class PathAliasTest extends PathTestBase {
$pid = $this->getPID($edit['alias']);
$previous = $edit['alias'];
$edit['alias'] = '/alias' . // Lower-case letters.
// Lower-case letters.
$edit['alias'] = '/alias' .
// "Special" ASCII characters.
"- ._~!$'\"()*@[]?&+%#,;=:" .
// Characters that look like a percent-escaped string.
@@ -246,7 +247,8 @@ class PathAliasTest extends PathTestBase {
$previous = $edit['path[0][alias]'];
// Change alias to one containing "exotic" characters.
$edit['path[0][alias]'] = '/alias' . // Lower-case letters.
// Lower-case letters.
$edit['path[0][alias]'] = '/alias' .
// "Special" ASCII characters.
"- ._~!$'\"()*@[]?&+%#,;=:" .
// Characters that look like a percent-escaped string.
@@ -0,0 +1,107 @@
<?php
namespace Drupal\Tests\path\Functional;
use Drupal\node\Entity\NodeType;
use Drupal\Tests\BrowserTestBase;
use Drupal\workflows\Entity\Workflow;
/**
* Tests path aliases with Content Moderation.
*
* @group content_moderation
* @group path
*/
class PathContentModerationTest extends BrowserTestBase {
/**
* Modules to install.
*
* @var array
*/
public static $modules = ['node', 'path', 'content_moderation'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Created a content type.
$node_type = NodeType::create(['name' => 'moderated', 'type' => 'moderated']);
$node_type->save();
// Set the content type as moderated.
$workflow = Workflow::load('editorial');
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'moderated');
$workflow->save();
$this->drupalLogin($this->rootUser);
}
/**
* Tests node path aliases on a moderated content type.
*/
public function testNodePathAlias() {
// Create some moderated content with a path alias.
$this->drupalGet('node/add/moderated');
$this->assertSession()->fieldValueEquals('path[0][alias]', '');
$this->drupalPostForm(NULL, [
'title[0][value]' => 'moderated content',
'path[0][alias]' => '/moderated-content',
'moderation_state[0][state]' => 'published',
], t('Save'));
$node = $this->getNodeByTitle('moderated content');
// Add a pending revision with the same alias.
$this->drupalGet('node/' . $node->id() . '/edit');
$this->assertSession()->fieldValueEquals('path[0][alias]', '/moderated-content');
$this->drupalPostForm(NULL, [
'title[0][value]' => 'pending revision',
'path[0][alias]' => '/moderated-content',
'moderation_state[0][state]' => 'draft',
], t('Save'));
$this->assertSession()->pageTextNotContains('You can only change the URL alias for the published version of this content.');
// Create some moderated content with no path alias.
$this->drupalGet('node/add/moderated');
$this->assertSession()->fieldValueEquals('path[0][alias]', '');
$this->drupalPostForm(NULL, [
'title[0][value]' => 'moderated content 2',
'path[0][alias]' => '',
'moderation_state[0][state]' => 'published',
], t('Save'));
$node = $this->getNodeByTitle('moderated content 2');
// Add a pending revision with a new alias.
$this->drupalGet('node/' . $node->id() . '/edit');
$this->assertSession()->fieldValueEquals('path[0][alias]', '');
$this->drupalPostForm(NULL, [
'title[0][value]' => 'pending revision',
'path[0][alias]' => '/pending-revision',
'moderation_state[0][state]' => 'draft',
], t('Save'));
$this->assertSession()->pageTextContains('You can only change the URL alias for the published version of this content.');
// Create some moderated content with no path alias.
$this->drupalGet('node/add/moderated');
$this->assertSession()->fieldValueEquals('path[0][alias]', '');
$this->drupalPostForm(NULL, [
'title[0][value]' => 'moderated content 3',
'path[0][alias]' => '',
'moderation_state[0][state]' => 'published',
], t('Save'));
$node = $this->getNodeByTitle('moderated content 3');
// Add a pending revision with no path alias.
$this->drupalGet('node/' . $node->id() . '/edit');
$this->assertSession()->fieldValueEquals('path[0][alias]', '');
$this->drupalPostForm(NULL, [
'title[0][value]' => 'pending revision',
'path[0][alias]' => '',
'moderation_state[0][state]' => 'draft',
], t('Save'));
$this->assertSession()->pageTextNotContains('You can only change the URL alias for the published version of this content.');
}
}
@@ -0,0 +1,176 @@
<?php
namespace Drupal\Tests\path\Kernel;
use Drupal\KernelTests\KernelTestBase;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
/**
* Tests loading and storing data using PathItem.
*
* @group path
*/
class PathItemTest extends KernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['path', 'node', 'user', 'system', 'language', 'content_translation'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('node');
$this->installEntitySchema('user');
$this->installSchema('node', ['node_access']);
$node_type = NodeType::create(['type' => 'foo']);
$node_type->save();
$this->installConfig(['language']);
ConfigurableLanguage::createFromLangcode('de')->save();
}
/**
* Test creating, loading, updating and deleting aliases through PathItem.
*/
public function testPathItem() {
/** @var \Drupal\Core\Path\AliasStorageInterface $alias_storage */
$alias_storage = \Drupal::service('path.alias_storage');
$node_storage = \Drupal::entityTypeManager()->getStorage('node');
$node = Node::create([
'title' => 'Testing create()',
'type' => 'foo',
'path' => ['alias' => '/foo'],
]);
$this->assertFalse($node->get('path')->isEmpty());
$this->assertEquals('/foo', $node->get('path')->alias);
$node->save();
$this->assertFalse($node->get('path')->isEmpty());
$this->assertEquals('/foo', $node->get('path')->alias);
$stored_alias = $alias_storage->lookupPathAlias('/' . $node->toUrl()->getInternalPath(), $node->language()->getId());
$this->assertEquals('/foo', $stored_alias);
$node_storage->resetCache();
/** @var \Drupal\node\NodeInterface $loaded_node */
$loaded_node = $node_storage->load($node->id());
$this->assertFalse($loaded_node->get('path')->isEmpty());
$this->assertEquals('/foo', $loaded_node->get('path')->alias);
$node_storage->resetCache();
$loaded_node = $node_storage->load($node->id());
$this->assertEquals('/foo', $loaded_node->get('path')[0]->get('alias')->getValue());
$node_storage->resetCache();
$loaded_node = $node_storage->load($node->id());
$values = $loaded_node->get('path')->getValue();
$this->assertEquals('/foo', $values[0]['alias']);
$node_storage->resetCache();
$loaded_node = $node_storage->load($node->id());
$this->assertEquals('/foo', $loaded_node->path->alias);
// Add a translation, verify it is being saved as expected.
$translation = $loaded_node->addTranslation('de', $loaded_node->toArray());
$translation->get('path')->alias = '/furchtbar';
$translation->save();
// Assert the alias on the English node, the German translation, and the
// stored aliases.
$node_storage->resetCache();
$loaded_node = $node_storage->load($node->id());
$this->assertEquals('/foo', $loaded_node->path->alias);
$translation = $loaded_node->getTranslation('de');
$this->assertEquals('/furchtbar', $translation->path->alias);
$stored_alias = $alias_storage->lookupPathAlias('/' . $node->toUrl()->getInternalPath(), $node->language()->getId());
$this->assertEquals('/foo', $stored_alias);
$stored_alias = $alias_storage->lookupPathAlias('/' . $node->toUrl()->getInternalPath(), $translation->language()->getId());
$this->assertEquals('/furchtbar', $stored_alias);
$loaded_node->get('path')->alias = '/bar';
$this->assertFalse($loaded_node->get('path')->isEmpty());
$this->assertEquals('/bar', $loaded_node->get('path')->alias);
$loaded_node->save();
$this->assertFalse($loaded_node->get('path')->isEmpty());
$this->assertEquals('/bar', $loaded_node->get('path')->alias);
$node_storage->resetCache();
$loaded_node = $node_storage->load($node->id());
$this->assertFalse($loaded_node->get('path')->isEmpty());
$this->assertEquals('/bar', $loaded_node->get('path')->alias);
$loaded_node->get('path')->alias = '/bar';
$this->assertFalse($loaded_node->get('path')->isEmpty());
$this->assertEquals('/bar', $loaded_node->get('path')->alias);
$loaded_node->save();
$this->assertFalse($loaded_node->get('path')->isEmpty());
$this->assertEquals('/bar', $loaded_node->get('path')->alias);
$stored_alias = $alias_storage->lookupPathAlias('/' . $node->toUrl()->getInternalPath(), $node->language()->getId());
$this->assertEquals('/bar', $stored_alias);
$old_alias = $alias_storage->lookupPathSource('/foo', $node->language()->getId());
$this->assertFalse($old_alias);
// Reload the node to make sure that it is possible to set a value
// immediately after loading.
$node_storage->resetCache();
$loaded_node = $node_storage->load($node->id());
$loaded_node->get('path')->alias = '/foobar';
$loaded_node->save();
$node_storage->resetCache();
$loaded_node = $node_storage->load($node->id());
$this->assertFalse($loaded_node->get('path')->isEmpty());
$this->assertEquals('/foobar', $loaded_node->get('path')->alias);
$stored_alias = $alias_storage->lookupPathAlias('/' . $node->toUrl()->getInternalPath(), $node->language()->getId());
$this->assertEquals('/foobar', $stored_alias);
$old_alias = $alias_storage->lookupPathSource('/bar', $node->language()->getId());
$this->assertFalse($old_alias);
$loaded_node->get('path')->alias = '';
$this->assertEquals('', $loaded_node->get('path')->alias);
$loaded_node->save();
$stored_alias = $alias_storage->lookupPathAlias('/' . $node->toUrl()->getInternalPath(), $node->language()->getId());
$this->assertFalse($stored_alias);
// Check that reading, updating and reading the computed alias again in the
// same request works without clearing any caches in between.
$loaded_node = $node_storage->load($node->id());
$loaded_node->get('path')->alias = '/foo';
$loaded_node->save();
$this->assertFalse($loaded_node->get('path')->isEmpty());
$this->assertEquals('/foo', $loaded_node->get('path')->alias);
$stored_alias = $alias_storage->lookupPathAlias('/' . $node->toUrl()->getInternalPath(), $node->language()->getId());
$this->assertEquals('/foo', $stored_alias);
$loaded_node->get('path')->alias = '/foobar';
$loaded_node->save();
$this->assertFalse($loaded_node->get('path')->isEmpty());
$this->assertEquals('/foobar', $loaded_node->get('path')->alias);
$stored_alias = $alias_storage->lookupPathAlias('/' . $node->toUrl()->getInternalPath(), $node->language()->getId());
$this->assertEquals('/foobar', $stored_alias);
}
}