Skip to content

Commit

Permalink
Merge branch '3.x' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
octoberapp committed Aug 14, 2023
2 parents 0392903 + c77ad97 commit 9930ef6
Show file tree
Hide file tree
Showing 10 changed files with 102 additions and 31 deletions.
39 changes: 37 additions & 2 deletions src/Database/Concerns/HasReplication.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,42 @@ trait HasReplication
*/
public function replicateWithRelations(array $except = null)
{
return $this->replicateRelationsInternal($except);
}

/**
* duplicateWithRelations replicates a model with special multisite duplication logic.
* To avoid duplication of has many relations, the logic only propagates relations on
* the parent model since they are shared via site_root_id beyond this point.
*
* @param array|null $except
* @return static
*/
public function duplicateWithRelations(array $except = null)
{
return $this->replicateRelationsInternal($except, ['isDuplicate' => true]);
}

/**
* replicateRelationsInternal
*/
protected function replicateRelationsInternal(array $except = null, array $options = [])
{
extract(array_merge([
'isDuplicate' => false
], $options));

$defaults = [
$this->getKeyName(),
$this->getCreatedAtColumn(),
$this->getUpdatedAtColumn(),
];

$isMultisite = $this->isClassInstanceOf(\October\Contracts\Database\MultisiteInterface::class);
if ($isMultisite) {
$defaults[] = 'site_root_id';
}

$attributes = Arr::except(
$this->attributes, $except ? array_unique(array_merge($except, $defaults)) : $defaults
);
Expand All @@ -39,7 +69,7 @@ public function replicateWithRelations(array $except = null)

foreach ($definitions as $type => $relations) {
foreach ($relations as $name => $options) {
if ($this->isRelationReplicable($name)) {
if ($this->isRelationReplicable($name, $isMultisite, $isDuplicate)) {
$this->replicateRelationInternal($instance->$name(), $this->$name);
}
}
Expand Down Expand Up @@ -77,13 +107,18 @@ protected function replicateRelationInternal($relationObject, $models)
* isRelationReplicable determines whether the specified relation should be replicated
* when replicateWithRelations() is called instead of save() on the model. Default: true.
*/
protected function isRelationReplicable(string $name): bool
protected function isRelationReplicable(string $name, bool $isMultisite, bool $isDuplicate): bool
{
$relationType = $this->getRelationType($name);
if ($relationType === 'morphTo') {
return false;
}

// Relation is shared via propagation
if (!$isDuplicate && $isMultisite && $this->isAttributePropagatable($name)) {
return false;
}

$definition = $this->getRelationDefinition($name);
if (!array_key_exists('replicate', $definition)) {
return true;
Expand Down
3 changes: 3 additions & 0 deletions src/Database/Model.php
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,9 @@ protected function saveInternal($options = [])
$this->commitDeferredAfter($this->sessionKey);
}

// After save deferred binding
$this->fireEvent('model.saveComplete');

return $result;
}

Expand Down
26 changes: 16 additions & 10 deletions src/Database/Relations/AttachOneOrMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,8 @@ public function addEagerConstraints(array $models)
*/
public function save(Model $model, $sessionKey = null)
{
// Delete siblings for single attachments
if ($sessionKey === null && $this instanceof AttachOne) {
$this->delete();
if ($sessionKey === null) {
$this->ensureAttachOneIsSingular();
}

if (!array_key_exists('is_public', $model->attributes)) {
Expand All @@ -134,9 +133,8 @@ public function save(Model $model, $sessionKey = null)
*/
public function create(array $attributes = [], $sessionKey = null)
{
// Delete siblings for single attachments
if ($sessionKey === null && $this instanceof AttachOne) {
$this->delete();
if ($sessionKey === null) {
$this->ensureAttachOneIsSingular();
}

if (!array_key_exists('is_public', $attributes)) {
Expand Down Expand Up @@ -181,10 +179,7 @@ public function add(Model $model, $sessionKey = null)
return;
}

// Delete siblings for single attachments
if ($this instanceof AttachOne) {
$this->delete();
}
$this->ensureAttachOneIsSingular();

// Associate the model
if ($this->parent->exists) {
Expand Down Expand Up @@ -320,6 +315,17 @@ protected function isModelRemovable($model): bool
$model->getAttribute('field') === $this->relationName;
}

/**
* ensureAttachOneIsSingular ensures AttachOne only has one attachment,
* by deleting siblings for singular relations.
*/
protected function ensureAttachOneIsSingular()
{
if ($this instanceof AttachOne && $this->parent->exists) {
$this->delete();
}
}

/**
* isValidFileData returns true if the specified value can be used as the data attribute
*/
Expand Down
4 changes: 2 additions & 2 deletions src/Database/Relations/HasMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ public function setSimpleValue($value)
// Nulling the relationship
if (!$value) {
if ($this->parent->exists) {
$this->parent->bindEventOnce('model.afterSave', function () {
$this->update([$this->getForeignKeyName() => null]);
$this->parent->bindEventOnce('model.afterSave', function() {
$this->ensureRelationIsEmpty();
});
}
return;
Expand Down
4 changes: 2 additions & 2 deletions src/Database/Relations/HasOne.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ public function setSimpleValue($value)
// Nulling the relationship
if (!$value) {
if ($this->parent->exists) {
$this->parent->bindEventOnce('model.afterSave', function () {
$this->update([$this->getForeignKeyName() => null]);
$this->parent->bindEventOnce('model.afterSave', function() {
$this->ensureRelationIsEmpty();
});
}
return;
Expand Down
15 changes: 15 additions & 0 deletions src/Database/Relations/HasOneOrMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,21 @@ protected function isModelRemovable($model): bool
return ((string) $model->getAttribute($this->getForeignKeyName()) === (string) $this->getParentKey());
}

/**
* ensureRelationIsEmpty ensures the relation is empty, either deleted or nulled.
*/
protected function ensureRelationIsEmpty()
{
$options = $this->parent->getRelationDefinition($this->relationName);

if (array_get($options, 'delete', false)) {
$this->delete();
}
else {
$this->update([$this->getForeignKeyName() => null]);
}
}

/**
* getRelatedKeyName
* @return string
Expand Down
5 changes: 1 addition & 4 deletions src/Database/Relations/MorphMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,7 @@ public function setSimpleValue($value)
if (!$value) {
if ($this->parent->exists) {
$this->parent->bindEventOnce('model.afterSave', function () {
$this->update([
$this->getForeignKeyName() => null,
$this->getMorphType() => null
]);
$this->ensureRelationIsEmpty();
});
}
return;
Expand Down
7 changes: 2 additions & 5 deletions src/Database/Relations/MorphOne.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,8 @@ public function setSimpleValue($value)
// Nulling the relationship
if (!$value) {
if ($this->parent->exists) {
$this->parent->bindEventOnce('model.afterSave', function () {
$this->update([
$this->getForeignKeyName() => null,
$this->getMorphType() => null
]);
$this->parent->bindEventOnce('model.afterSave', function() {
$this->ensureRelationIsEmpty();
});
}
return;
Expand Down
18 changes: 18 additions & 0 deletions src/Database/Relations/MorphOneOrMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,24 @@ protected function isModelRemovable($model): bool
$model->getAttribute($this->getMorphType()) === $this->morphClass;
}

/**
* ensureRelationIsEmpty ensures the relation is empty, either deleted or nulled.
*/
protected function ensureRelationIsEmpty()
{
$options = $this->parent->getRelationDefinition($this->relationName);

if (array_get($options, 'delete', false)) {
$this->delete();
}
else {
$this->update([
$this->getForeignKeyName() => null,
$this->getMorphType() => null
]);
}
}

/**
* getRelatedKeyName
* @return string
Expand Down
12 changes: 6 additions & 6 deletions src/Database/Traits/Multisite.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,15 @@ public function initializeMultisite()

$this->bindEvent('model.beforeSave', [$this, 'multisiteBeforeSave']);

$this->bindEvent('model.afterSave', [$this, 'multisiteAfterSave']);

$this->bindEvent('model.afterCreate', [$this, 'multisiteAfterCreate']);

$this->bindEvent('model.saveComplete', [$this, 'multisiteSaveComplete']);

$this->defineMultisiteRelations();
}

/**
* multisiteBeforeSave constructor event
* multisiteBeforeSave constructor event used internally
*/
public function multisiteBeforeSave()
{
Expand All @@ -67,9 +67,9 @@ public function multisiteBeforeSave()
}

/**
* multisiteAfterSave constructor event
* multisiteSaveComplete constructor event used internally
*/
public function multisiteAfterSave()
public function multisiteSaveComplete()
{
if ($this->getSaveOption('propagate') !== true) {
return;
Expand Down Expand Up @@ -101,7 +101,7 @@ public function multisiteAfterSave()
}

/**
* multisiteAfterCreate constructor event
* multisiteAfterCreate constructor event used internally
*/
public function multisiteAfterCreate()
{
Expand Down

0 comments on commit 9930ef6

Please sign in to comment.