Issue #2302137 by alexpott, dawehner, pwolanin, xjm, kgoel, catch: Improve performance when menu link value matches with the original value

8.4.x
Nathaniel Catchpole 2017-05-11 17:19:11 +01:00
parent 39803eb1f6
commit 1228959c51
1 changed files with 28 additions and 11 deletions

View File

@ -282,27 +282,44 @@ class MenuTreeStorage implements MenuTreeStorageInterface {
* depth.
*/
protected function doSave(array $link) {
$original = $this->loadFull($link['id']);
// @todo Should we just return here if the link values match the original
// values completely?
// https://www.drupal.org/node/2302137
$affected_menus = [];
// Get the existing definition if it exists. This does not use
// self::loadFull() to avoid the unserialization of fields with 'serialize'
// equal to TRUE as defined in self::schemaDefinition(). The makes $original
// easier to compare with the return value of self::preSave().
$query = $this->connection->select($this->table, $this->options);
$query->fields($this->table);
$query->condition('id', $link['id']);
$original = $this->safeExecuteSelect($query)->fetchAssoc();
if ($original) {
$link['mlid'] = $original['mlid'];
$link['has_children'] = $original['has_children'];
$affected_menus[$original['menu_name']] = $original['menu_name'];
$fields = $this->preSave($link, $original);
// If $link matches the $original data then exit early as there are no
// changes to make. Use array_diff_assoc() to check if they match because:
// - Some of the data types of the values are not the same. The values
// in $original are all strings because they have come from database but
// $fields contains typed values.
// - MenuTreeStorage::preSave() removes the 'mlid' from $fields.
// - The order of the keys in $original and $fields is different.
if (array_diff_assoc($fields, $original) == [] && array_diff_assoc($original, $fields) == ['mlid' => $link['mlid']]) {
return $affected_menus;
}
}
$transaction = $this->connection->startTransaction();
try {
if ($original) {
$link['mlid'] = $original['mlid'];
$link['has_children'] = $original['has_children'];
$affected_menus[$original['menu_name']] = $original['menu_name'];
}
else {
if (!$original) {
// Generate a new mlid.
$options = ['return' => Database::RETURN_INSERT_ID] + $this->options;
$link['mlid'] = $this->connection->insert($this->table, $options)
->fields(['id' => $link['id'], 'menu_name' => $link['menu_name']])
->execute();
$fields = $this->preSave($link, []);
}
$fields = $this->preSave($link, $original);
// We may be moving the link to a new menu.
$affected_menus[$fields['menu_name']] = $fields['menu_name'];
$query = $this->connection->update($this->table, $this->options);