Skip to content

Commit

Permalink
Structure locks (#3148)
Browse files Browse the repository at this point in the history
  • Loading branch information
brandonkelly committed Jul 24, 2018
1 parent cdf8c92 commit bb3d55e
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 2 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG-v3.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Release Notes for Craft CMS 3.x

## Unreleased

### Changed
- Structure operations now ensure that no other operations are being performed on the same structure, reducing the risk of corrupting the structure. ([#3148](https://github.com/craftcms/cms/issues/3148))

## 3.0.17.1 - 2018-07-24

### Fixed
Expand Down
14 changes: 12 additions & 2 deletions src/services/Structures.php
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,13 @@ private function _getRootElementRecord(int $structureId): StructureElement
*/
private function _doIt($structureId, ElementInterface $element, StructureElement $targetElementRecord, $action, $mode): bool
{
// Get a lock or bust
$lockName = 'structure:' . $structureId;
$mutex = Craft::$app->getMutex();
if (!$mutex->acquire($lockName)) {
throw new Exception('Unable to acquire a lock for the structure ' . $structureId);
}

$elementRecord = null;

/** @var Element $element */
Expand Down Expand Up @@ -376,14 +383,15 @@ private function _doIt($structureId, ElementInterface $element, StructureElement

// Tell the element about it
if (!$element->beforeMoveInStructure($structureId)) {
$mutex->release($lockName);
return false;
}

$transaction = Craft::$app->getDb()->beginTransaction();
try {
if (!$elementRecord->$action($targetElementRecord)) {
$transaction->rollBack();

$mutex->release($lockName);
return false;
}

Expand All @@ -409,10 +417,12 @@ private function _doIt($structureId, ElementInterface $element, StructureElement
$transaction->commit();
} catch (\Throwable $e) {
$transaction->rollBack();

$mutex->release($lockName);
throw $e;
}

$mutex->release($lockName);

if ($mode === 'update' && $this->hasEventHandlers(self::EVENT_AFTER_MOVE_ELEMENT)) {
// Fire an 'afterMoveElement' event
$this->trigger(self::EVENT_AFTER_MOVE_ELEMENT, new MoveElementEvent([
Expand Down

0 comments on commit bb3d55e

Please sign in to comment.