From f1fb16fc95508a335c516f16e5b0e4aa23ea3b0e Mon Sep 17 00:00:00 2001 From: ilestis Date: Sat, 2 Dec 2023 09:50:12 -0600 Subject: [PATCH 1/5] Replace nested trees with common table expressions --- app/Console/Commands/GenerateTrees.php | 78 - app/Http/Controllers/CrudController.php | 2 +- .../Locations/CharacterController.php | 1 + .../Locations/LocationController.php | 2 +- app/Models/Ability.php | 17 +- app/Models/AttributeTemplate.php | 14 +- app/Models/Calendar.php | 2 +- app/Models/Concerns/HasFilters.php | 2 +- app/Models/Concerns/Nested.php | 1262 ----------------- app/Models/Creature.php | 16 +- app/Models/Event.php | 40 +- app/Models/Family.php | 14 +- app/Models/Item.php | 2 +- app/Models/Journal.php | 14 +- app/Models/Location.php | 18 +- app/Models/Map.php | 13 +- app/Models/MiscModel.php | 2 - app/Models/Note.php | 14 +- app/Models/Organisation.php | 16 +- app/Models/Quest.php | 14 +- app/Models/Race.php | 18 +- app/Models/Tag.php | 26 +- app/Models/Timeline.php | 30 +- app/Observers/AbilityObserver.php | 2 - app/Observers/AttributeTemplateObserver.php | 2 - app/Observers/CreatureObserver.php | 2 - app/Observers/EventObserver.php | 2 - app/Observers/FamilyObserver.php | 2 - app/Observers/JournalObserver.php | 2 - app/Observers/LocationObserver.php | 2 - app/Observers/MapObserver.php | 2 - app/Observers/MiscObserver.php | 31 - app/Observers/NoteObserver.php | 2 - app/Observers/OrganisationObserver.php | 5 +- app/Observers/RaceObserver.php | 2 - app/Observers/TagObserver.php | 4 +- app/Observers/TimelineObserver.php | 2 - .../Campaign/Import/ImportService.php | 2 +- .../Campaign/Import/Mappers/EntityMapper.php | 11 - app/Services/Entity/EntityRelationService.php | 2 +- app/Services/Entity/MoveService.php | 4 - app/Services/Entity/TransformService.php | 7 - app/Services/RecoveryService.php | 10 +- app/Traits/CanFixTree.php | 45 - app/Traits/ExportableTrait.php | 4 +- app/Traits/TreeControllerTrait.php | 2 +- composer.json | 2 + composer.lock | 165 ++- .../2023_12_02_154727_remove_old_trees.php | 51 + 49 files changed, 287 insertions(+), 1697 deletions(-) delete mode 100644 app/Console/Commands/GenerateTrees.php delete mode 100644 app/Models/Concerns/Nested.php delete mode 100644 app/Traits/CanFixTree.php create mode 100644 database/migrations/2023_12_02_154727_remove_old_trees.php diff --git a/app/Console/Commands/GenerateTrees.php b/app/Console/Commands/GenerateTrees.php deleted file mode 100644 index 2bd692edb8..0000000000 --- a/app/Console/Commands/GenerateTrees.php +++ /dev/null @@ -1,78 +0,0 @@ -out('Start fixing trees'); - $models = explode(',', $this->argument('models')); - - if ($this->argument('models') === 'all') { - $this->fixAll(); - $this->info('Finished'); - return 1; - } - - $classes = config('entities.classes'); - foreach ($models as $model) { - $class = new $classes[$model](); - if ($class === false || !method_exists($class, 'recalculateTreeBounds')) { - $this->warn('Skipping ' . $model); - continue; - } - $start = Carbon::now(); - $this->out("Model {$model}"); - $class::fixTree(); - $end = Carbon::now(); - $this->out('Fixed in ' . $start->diffInMinutes($end) . ' minutes'); - } - $this->out('Finished fixing trees'); - } - - /** - * - */ - protected function fixAll(): void - { - $models = config('entities.classes'); - foreach ($models as $model => $class) { - $new = new $class(); - try { - $this->info("Fixing {$model}"); - $class::fixTree(); - } catch (Exception $e) { - $this->warn('Skipping ' . $model); - } - } - } - - protected function out(string $text): self - { - $now = Carbon::now(); - $this->info($now->format('H:i:s') . ': ' . $text); - return $this; - } -} diff --git a/app/Http/Controllers/CrudController.php b/app/Http/Controllers/CrudController.php index 5f2eb8d657..0500a135c6 100644 --- a/app/Http/Controllers/CrudController.php +++ b/app/Http/Controllers/CrudController.php @@ -144,7 +144,7 @@ public function crudIndex(Request $request) $parent = null; if (request()->has('parent_id')) { // @phpstan-ignore-next-line - $parentKey = $model->getParentIdName(); + $parentKey = $model->getParentKeyName(); $base->where([$model->getTable() . '.' . $parentKey => request()->get('parent_id')]); $parent = $model->where('id', request()->get('parent_id'))->first(); diff --git a/app/Http/Controllers/Locations/CharacterController.php b/app/Http/Controllers/Locations/CharacterController.php index dc98a679e1..ee2d55152b 100644 --- a/app/Http/Controllers/Locations/CharacterController.php +++ b/app/Http/Controllers/Locations/CharacterController.php @@ -38,6 +38,7 @@ public function index(Campaign $campaign, Location $location) 'location', 'location.entity', 'races', 'families', ]) + ->filter($filters) ->filteredCharacters() ->paginate(); diff --git a/app/Http/Controllers/Locations/LocationController.php b/app/Http/Controllers/Locations/LocationController.php index 6e36808181..3ec7a128df 100644 --- a/app/Http/Controllers/Locations/LocationController.php +++ b/app/Http/Controllers/Locations/LocationController.php @@ -34,7 +34,7 @@ public function index(Campaign $campaign, Location $location) // @phpstan-ignore-next-line $this->rows = $location ->descendants() - ->select(['id', 'image', 'name', 'type', 'location_id', 'is_private']) + ->select(['id', 'name', 'type', 'location_id', 'is_private']) ->sort(request()->only(['o', 'k']), ['name' => 'asc']) ->filter($filters) ->with([ diff --git a/app/Models/Ability.php b/app/Models/Ability.php index d9e0ef456f..82f59c1518 100644 --- a/app/Models/Ability.php +++ b/app/Models/Ability.php @@ -14,6 +14,7 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Support\Arr; +use Staudenmeir\LaravelAdjacencyList\Eloquent\HasRecursiveRelationships; /** * Class Ability @@ -34,10 +35,9 @@ class Ability extends MiscModel use CampaignTrait; use ExportableTrait; use HasFactory; - use Nested; + use HasRecursiveRelationships; use SoftDeletes; - use SortableTrait - ; + use SortableTrait; /** @var string[] */ protected $fillable = [ @@ -86,20 +86,11 @@ class Ability extends MiscModel * Parent ID used for the Node Trait * @return string */ - public function getParentIdName() + public function getParentKeyName() { return 'ability_id'; } - /** - * Specify parent id attribute mutator - * @param int $value - */ - public function setAbilityIdAttribute($value) - { - $this->setParentIdAttribute($value); - } - /** * Performance with for datagrids */ diff --git a/app/Models/AttributeTemplate.php b/app/Models/AttributeTemplate.php index 1f89e39559..9f7edbf859 100644 --- a/app/Models/AttributeTemplate.php +++ b/app/Models/AttributeTemplate.php @@ -8,6 +8,7 @@ use App\Traits\CampaignTrait; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\SoftDeletes; +use Staudenmeir\LaravelAdjacencyList\Eloquent\HasRecursiveRelationships; /** * Class AttributeTemplate @@ -23,7 +24,7 @@ class AttributeTemplate extends MiscModel { use Acl; use CampaignTrait; - use Nested; + use HasRecursiveRelationships; use SoftDeletes; /** @@ -96,20 +97,11 @@ public function attributeTemplates() * Parent ID field for the Node trait * @return string */ - public function getParentIdName() + public function getParentKeyName() { return 'attribute_template_id'; } - /** - * Specify parent id attribute mutator - * @param int $value - */ - public function setAttributeTemplateIdAttribute($value) - { - $this->setParentIdAttribute($value); - } - /** * Performance with for datagrids */ diff --git a/app/Models/Calendar.php b/app/Models/Calendar.php index 20256e1ac8..3fc5d261fc 100644 --- a/app/Models/Calendar.php +++ b/app/Models/Calendar.php @@ -134,7 +134,7 @@ public function datagridSelectFields(): array return ['calendar_id', 'date']; } - public function getParentIdName(): string + public function getParentKeyName(): string { return 'calendar_id'; } diff --git a/app/Models/Concerns/HasFilters.php b/app/Models/Concerns/HasFilters.php index accba884f0..c0a9eaf12c 100644 --- a/app/Models/Concerns/HasFilters.php +++ b/app/Models/Concerns/HasFilters.php @@ -650,6 +650,6 @@ protected function getFilterOption(): FilterOption protected function filterParent(Builder $query): void { - $query->where($this->getTable() . '.' . $this->getParentIdName(), $this->filterValue); + $query->where($this->getTable() . '.' . $this->getParentKeyName(), $this->filterValue); } } diff --git a/app/Models/Concerns/Nested.php b/app/Models/Concerns/Nested.php deleted file mode 100644 index e5aa018827..0000000000 --- a/app/Models/Concerns/Nested.php +++ /dev/null @@ -1,1262 +0,0 @@ -callPendingAction(); - }); - - static::deleting(function ($model) { - // We will need fresh data to delete node safely - $model->refreshNode(); - }); - - static::deleted(function ($model) { - // We don't want this feature of the nested plugin, so we just ignore it :) - //$model->deleteDescendants(); - }); - - if (static::usesSoftDelete()) { - static::restoring(function ($model) { - static::$deletedAt = $model->{$model->getDeletedAtColumn()}; - }); - - static::restored(function ($model) { - //$model->restoreDescendants(static::$deletedAt); - }); - } - } - - /** - * Set an action. - * - * @param string $action - * - * @return $this - */ - protected function setNodeAction($action) - { - $this->pending = func_get_args(); - - return $this; - } - - public function forcePendingAction() - { - $this->callPendingAction(); - } - - /** - * Call pending action. - */ - protected function callPendingAction() - { - $this->moved = false; - - if (!$this->pending && !$this->exists) { - $this->makeRoot(); - } - - if (!$this->pending) { - return; - } - - $method = 'action' . ucfirst(array_shift($this->pending)); - //dump($method); - $parameters = $this->pending; - - $this->pending = null; - - $this->moved = call_user_func_array([$this, $method], $parameters); - } - - /** - * Force this element to recalculate the tree bounds if it's being created - */ - public function recalculateTreeBounds() - { - // No need if this entity exists - //dump('recalculate Tree Bounds'); - if ($this->exists) { - return; - } - - $value = $this->getParentId(); - if ($value) { - $this->appendToNode($this->newScopedQuery()->findOrFail($value)); - } else { - $this->actionRoot(); - } - } - - /** - * Force a node as root. Useful when moving an entity to another campaign - */ - public function forceAsRoot(): void - { - if (!$this->exists) { - Log::warning('Trying to force a non-existing model as a tree root.'); - } - $this->actionRoot(); - } - - /** - * @return bool - */ - public static function usesSoftDelete() - { - static $softDelete; - - if (null === $softDelete) { - $instance = new static(); - - return $softDelete = method_exists($instance, 'bootSoftDeletes'); - } - - return $softDelete; - } - - /** - * @return bool - */ - protected function actionRaw() - { - return true; - } - - /** - * Make a root node. - */ - protected function actionRoot() - { - // Simplest case that do not affect other nodes. - if (!$this->exists) { - $cut = $this->getLowerBound() + 1; - - $this->setLft($cut); - $this->setRgt($cut + 1); - - //dump($this->getBounds()); - return true; - } - //dump('exists'); - //dump($this->getLowerBound() + 1); - - return $this->insertAt($this->getLowerBound() + 1); - } - - /** - * Get the lower bound. - * - * @return int - */ - protected function getLowerBound() - { - // @phpstan-ignore-next-line - return (int)$this->newNestedSetQuery()->max($this->getRgtName()); - } - - /** - * Append or prepend a node to the parent. - * - * @param bool $prepend - * - * @return bool - */ - protected function actionAppendOrPrepend(self $parent, $prepend = false) - { - $parent->refreshNode(); - - $cut = $prepend ? $parent->getLft() + 1 : $parent->getRgt(); - - if (!$this->insertAt($cut)) { - return false; - } - - $parent->refreshNode(); - - return true; - } - - /** - * Apply parent model. - * - * @param Model|null $value - * - * @return $this - */ - protected function setParent($value) - { - $this->setParentId($value ? $value->getKey() : null) - ->setRelation('parent', $value); - - return $this; - } - - /** - * Insert node before or after another node. - * - * @param bool $after - * - * @return bool - */ - protected function actionBeforeOrAfter(self $node, $after = false) - { - $node->refreshNode(); - - return $this->insertAt($after ? $node->getRgt() + 1 : $node->getLft()); - } - - /** - * Refresh node's crucial attributes. - */ - public function refreshNode() - { - if (!$this->exists || static::$actionsPerformed === 0) { - return; - } - - $attributes = $this->newNestedSetQuery()->getNodeData($this->getKey()); - - $this->attributes = array_merge($this->attributes, $attributes); - // $this->original = array_merge($this->original, $attributes); - } - - /** - * Relation to the parent. - * - * @return BelongsTo - */ - public function parent() - { - return $this->belongsTo(get_class($this), $this->getParentIdName()) - ->setModel($this); - } - - /** - * Relation to children. - * - * @return HasMany - */ - public function children() - { - return $this->hasMany(get_class($this), $this->getParentIdName()) - ->setModel($this); - } - - /** - * Get query for descendants of the node. - * - * @return DescendantsRelation|Builder - */ - public function descendants() - { - // @phpstan-ignore-next-line - return new DescendantsRelation($this->newQuery(), $this); - } - - /** - * Get query for siblings of the node. - * - * @return QueryBuilder - */ - public function siblings() - { - return $this->newScopedQuery() - ->where($this->getKeyName(), '<>', $this->getKey()) - ->where($this->getParentIdName(), '=', $this->getParentId()); - } - - /** - * Get the node siblings and the node itself. - * - * @return \Kalnoy\Nestedset\QueryBuilder - */ - public function siblingsAndSelf() - { - return $this->newScopedQuery() - ->where($this->getParentIdName(), '=', $this->getParentId()); - } - - /** - * Get query for the node siblings and the node itself. - * - * - * @return \Illuminate\Database\Eloquent\Collection - */ - public function getSiblingsAndSelf(array $columns = ['*']) - { - return $this->siblingsAndSelf()->get($columns); - } - - /** - * Get query for siblings after the node. - * - * @return QueryBuilder - */ - public function nextSiblings() - { - return $this->nextNodes() - ->where($this->getParentIdName(), '=', $this->getParentId()); - } - - /** - * Get query for siblings before the node. - * - * @return QueryBuilder - */ - public function prevSiblings() - { - return $this->prevNodes() - ->where($this->getParentIdName(), '=', $this->getParentId()); - } - - /** - * Get query for nodes after current node. - * - * @return QueryBuilder - */ - public function nextNodes() - { - return $this->newScopedQuery() - ->where($this->getLftName(), '>', $this->getLft()); - } - - /** - * Get query for nodes before current node in reversed order. - * - * @return QueryBuilder - */ - public function prevNodes() - { - return $this->newScopedQuery() - ->where($this->getLftName(), '<', $this->getLft()); - } - - /** - * Get query ancestors of the node. - * - * @return AncestorsRelation|Builder - */ - public function ancestors() - { - // @phpstan-ignore-next-line - return new AncestorsRelation($this->newQuery(), $this); - } - - /** - * Make this node a root node. - * - * @return $this - */ - public function makeRoot() - { - $this->setParent(null)->dirtyBounds(); - - return $this->setNodeAction('root'); - } - - /** - * Save node as root. - * - * @return bool - */ - public function saveAsRoot() - { - if ($this->exists && $this->isRoot()) { - return $this->save(); - } - - return $this->makeRoot()->save(); - } - - /** - * Append and save a node. - * - * - * @return bool - */ - public function appendNode(self $node) - { - return $node->appendToNode($this)->save(); - } - - /** - * Prepend and save a node. - * - * - * @return bool - */ - public function prependNode(self $node) - { - return $node->prependToNode($this)->save(); - } - - /** - * Append a node to the new parent. - * - * - * @return $this - */ - public function appendToNode(self $parent) - { - // @phpstan-ignore-next-line - return $this->appendOrPrependTo($parent); - } - - /** - * Prepend a node to the new parent. - * - * - * @return $this - */ - public function prependToNode(self $parent) - { - // @phpstan-ignore-next-line - return $this->appendOrPrependTo($parent, true); - } - - /** - * - * @return self - */ - public function appendOrPrependTo(self $parent, bool $prepend = false) - { - $this->assertNodeExists($parent) - ->assertNotDescendant($parent) - ->assertSameScope($parent); - - $this->setParent($parent)->dirtyBounds(); - - return $this->setNodeAction('appendOrPrepend', $parent, $prepend); - } - - /** - * Insert self after a node. - * - * - * @return self - */ - public function afterNode(self $node) - { - return $this->beforeOrAfterNode($node, true); - } - - /** - * Insert self before node. - * - * - * @return self - */ - public function beforeNode(self $node) - { - return $this->beforeOrAfterNode($node); - } - - /** - * @param bool $after - * - * @return self - */ - public function beforeOrAfterNode(self $node, $after = false) - { - $this->assertNodeExists($node) - ->assertNotDescendant($node) - ->assertSameScope($node); - - if (!$this->isSiblingOf($node)) { - $this->setParent($node->getRelationValue('parent')); - } - - $this->dirtyBounds(); - - return $this->setNodeAction('beforeOrAfter', $node, $after); - } - - /** - * Insert self after a node and save. - * - * - * @return bool - */ - public function insertAfterNode(self $node) - { - return $this->afterNode($node)->save(); - } - - /** - * Insert self before a node and save. - * - * - * @return bool - */ - public function insertBeforeNode(self $node) - { - if (!$this->beforeNode($node)->save()) { - return false; - } - - // We'll update the target node since it will be moved - $node->refreshNode(); - - return true; - } - - /** - * - * @return $this - */ - public function rawNode(mixed $lft, mixed $rgt, mixed $parentId) - { - $this->setLft($lft)->setRgt($rgt)->setParentId($parentId); - - return $this->setNodeAction('raw'); - } - - /** - * Move node up given amount of positions. - * - * @param int $amount - * - * @return bool - */ - public function up($amount = 1) - { - // @phpstan-ignore-next-line - $sibling = $this->prevSiblings() - ->defaultOrder('desc') - ->skip($amount - 1) - ->first(); - - if (!$sibling) { - return false; - } - - return $this->insertBeforeNode($sibling); - } - - /** - * Move node down given amount of positions. - * - * @param int $amount - * - * @return bool - */ - public function down($amount = 1) - { - // @phpstan-ignore-next-line - $sibling = $this->nextSiblings() - ->defaultOrder() - ->skip($amount - 1) - ->first(); - - if (!$sibling) { - return false; - } - - return $this->insertAfterNode($sibling); - } - - /** - * Insert node at specific position. - * - * @param int $position - * - * @return bool - */ - protected function insertAt($position) - { - ++static::$actionsPerformed; - - $result = $this->exists - ? $this->moveNode($position) - : $this->insertNode($position); - - return $result; - } - - /** - * Move a node to the new position. - * - * @since 2.0 - * - * @param int $position - */ - protected function moveNode($position) - { - $updated = $this->newNestedSetQuery() - ->moveNode($this->getKey(), $position) > 0; - - if ($updated) { - $this->refreshNode(); - } - - return $updated; - } - - /** - * Insert new node at specified position. - * - * @since 2.0 - * - * @param int $position - * - * @return bool - */ - protected function insertNode($position) - { - $this->newNestedSetQuery()->makeGap($position, 2); - - $height = $this->getNodeHeight(); - - $this->setLft($position); - $this->setRgt($position + $height - 1); - - return true; - } - - /** - * Update the tree when the node is removed physically. - */ - protected function deleteDescendants() - { - $lft = $this->getLft(); - $rgt = $this->getRgt(); - - $method = $this->usesSoftDelete() && $this->forceDeleting - ? 'forceDelete' - : 'delete'; - - $this->descendants()->{$method}(); - - if ($this->hardDeleting()) { - $height = $rgt - $lft + 1; - - $this->newNestedSetQuery()->makeGap($rgt + 1, -$height); - - // In case if user wants to re-create the node - $this->makeRoot(); - - static::$actionsPerformed++; - } - } - - /** - * Restore the descendants. - * - */ - protected function restoreDescendants(string $deletedAt) - { - // @phpstan-ignore-next-line - $this->descendants() - ->where($this->getDeletedAtColumn(), '>=', $deletedAt) - ->restore(); - } - - /** - * {@inheritdoc} - * - * @since 2.0 - */ - public function newEloquentBuilder($query) - { - return new TreeQueryBuilder($query); - } - - /** - * Get a new base query that includes deleted nodes. - * - * @since 1.1 - * - * @return QueryBuilder - */ - public function newNestedSetQuery($table = null) - { - $builder = $this->usesSoftDelete() - ? $this->withTrashed() - : $this->newQuery(); - - return $this->applyNestedSetScope($builder, $table); - } - - /** - */ - public function newScopedQuery(string $table = null) - { - return $this->applyNestedSetScope($this->newQuery(), $table); - } - - /** - * @param string $table - * - */ - public function applyNestedSetScope($query, $table = null) - { - // @phpstan-ignore-next-line - if (!$scoped = $this->getScopeAttributes()) { - return $query; - } - - // @phpstan-ignore-next-line - if (!$table) { - $table = $this->getTable(); - } - - foreach ($scoped as $attribute) { - $query->where( - $table . '.' . $attribute, - '=', - $this->getAttributeValue($attribute) - ); - } - - return $query; - } - - /** - */ - protected function getScopeAttributes() - { - return null; - } - - /** - * - * @return self - */ - public static function scoped(array $attributes) - { - $instance = new static(); - - $instance->setRawAttributes($attributes); - - return $instance->newScopedQuery(); - } - - /** - * {@inheritdoc} - */ - public function newCollection(array $models = []) - { - return new Collection($models); - } - - /** - * {@inheritdoc} - * - * Use `children` key on `$attributes` to create child nodes. - * - */ - public static function create(array $attributes = [], self $parent = null) - { - $children = Arr::pull($attributes, 'children'); - - $instance = new static($attributes); - - if ($parent) { - $instance->appendToNode($parent); - } - - $instance->save(); - - // Now create children - $relation = new EloquentCollection(); - - foreach ((array)$children as $child) { - $relation->add($child = static::create($child, $instance)); - - $child->setRelation('parent', $instance); - } - - $instance->refreshNode(); - - return $instance->setRelation('children', $relation); - } - - /** - * Get node height (rgt - lft + 1). - * - * @return int - */ - public function getNodeHeight() - { - if (!$this->exists) { - return 2; - } - - return $this->getRgt() - $this->getLft() + 1; - } - - /** - * Get number of descendant nodes. - * - * @return int|float - */ - public function getDescendantCount() - { - return ceil($this->getNodeHeight() / 2) - 1; - } - - /** - * Set the value of model's parent id key. - * - * Behind the scenes node is appended to found parent node. - * - * @param int $value - * - * @throws Exception If parent node doesn't exists - */ - public function setParentIdAttribute($value) - { - if ($this->getParentId() == $value) { - return; - } - - if ($value) { - $this->appendToNode($this->newScopedQuery()->findOrFail($value)); - } else { - $this->makeRoot(); - } - } - - /** - * Get whether node is root. - * - * @return boolean - */ - public function isRoot() - { - // @phpstan-ignore-next-line - return null === $this->getParentId(); - } - - /** - * @return bool - */ - public function isLeaf() - { - return $this->getLft() + 1 == $this->getRgt(); - } - - /** - * Get the lft key name. - * - * @return string - */ - public function getLftName() - { - return NestedSet::LFT; - } - - /** - * Get the rgt key name. - * - * @return string - */ - public function getRgtName() - { - return NestedSet::RGT; - } - - /** - * Get the parent id key name. - * - * @return string - */ - public function getParentIdName() - { - return NestedSet::PARENT_ID; - } - - /** - * Get the value of the model's lft key. - * - * @return integer - */ - public function getLft() - { - return $this->getAttributeValue($this->getLftName()); - } - - /** - * Get the value of the model's rgt key. - * - * @return integer - */ - public function getRgt() - { - return $this->getAttributeValue($this->getRgtName()); - } - - /** - * Get the value of the model's parent id key. - * - * @return integer - */ - public function getParentId() - { - return $this->getAttributeValue($this->getParentIdName()); - } - - /** - * Returns node that is next to current node without constraining to siblings. - * - * This can be either a next sibling or a next sibling of the parent node. - * - * - * @return Model|null - */ - public function getNextNode(array $columns = ['*']) - { - return $this->nextNodes()->defaultOrder()->first($columns); - } - - /** - * Returns node that is before current node without constraining to siblings. - * - * This can be either a prev sibling or parent node. - * - * - * @return Model|null - */ - public function getPrevNode(array $columns = ['*']) - { - return $this->prevNodes()->defaultOrder('desc')->first($columns); - } - - /** - * - * @return \Illuminate\Database\Eloquent\Collection - */ - public function getAncestors(array $columns = ['*']) - { - return $this->ancestors()->get($columns); - } - - /** - * - * @return \Illuminate\Database\Eloquent\Collection - */ - public function getDescendants(array $columns = ['*']) - { - return $this->descendants()->get($columns); - } - - /** - * - * @return \Illuminate\Database\Eloquent\Collection - */ - public function getSiblings(array $columns = ['*']) - { - return $this->siblings()->get($columns); - } - - /** - */ - public function getNextSiblings(array $columns = ['*']) - { - return $this->nextSiblings()->get($columns); - } - - /** - */ - public function getPrevSiblings(array $columns = ['*']) - { - return $this->prevSiblings()->get($columns); - } - - /** - * @return Model|QueryBuilder|object|null - */ - public function getNextSibling(array $columns = ['*']) - { - return $this->nextSiblings()->defaultOrder()->first($columns); - } - - /** - * @return Model|QueryBuilder|object|null - */ - public function getPrevSibling(array $columns = ['*']) - { - return $this->prevSiblings()->defaultOrder('desc')->first($columns); - } - - /** - * Get whether a node is a descendant of other node. - * - * - * @return bool - */ - public function isDescendantOf(self $other) - { - return $this->getLft() > $other->getLft() && - $this->getLft() < $other->getRgt(); - } - - /** - * Get whether a node is itself or a descendant of other node. - * - * - * @return bool - */ - public function isSelfOrDescendantOf(self $other) - { - return $this->getLft() >= $other->getLft() && - $this->getLft() < $other->getRgt(); - } - - /** - * Get whether the node is immediate children of other node. - * - * - * @return bool - */ - public function isChildOf(self $other) - { - return $this->getParentId() == $other->getKey(); - } - - /** - * Get whether the node is a sibling of another node. - * - * - * @return bool - */ - public function isSiblingOf(self $other) - { - return $this->getParentId() == $other->getParentId(); - } - - /** - * Get whether the node is an ancestor of other node, including immediate parent. - * - * - * @return bool - */ - public function isAncestorOf(self $other) - { - return $other->isDescendantOf($this); - } - - /** - * Get whether the node is itself or an ancestor of other node, including immediate parent. - * - * - * @return bool - */ - public function isSelfOrAncestorOf(self $other) - { - return $other->isSelfOrDescendantOf($this); - } - - /** - * Get whether the node has moved since last save. - * - * @return bool - */ - public function hasMoved() - { - return $this->moved; - } - - /** - * @return array - */ - protected function getArrayableRelations() - { - $result = parent::getArrayableRelations(); - - // To fix #17 when converting tree to json falling to infinite recursion. - unset($result['parent']); - - return $result; - } - - /** - * Get whether user is intended to delete the model from database entirely. - * - * @return bool - */ - protected function hardDeleting() - { - return !$this->usesSoftDelete() || $this->forceDeleting; - } - - /** - * @return array - */ - public function getBounds() - { - return [$this->getLft(), $this->getRgt()]; - } - - /** - * - * @return $this - */ - public function setLft(int $value) - { - $this->attributes[$this->getLftName()] = $value; - - return $this; - } - - /** - * - * @return $this - */ - public function setRgt(int $value) - { - $this->attributes[$this->getRgtName()] = $value; - - return $this; - } - - /** - * - * @return $this - */ - public function setParentId(int|null $value) - { - $this->attributes[$this->getParentIdName()] = $value; - - return $this; - } - - /** - * @return $this - */ - protected function dirtyBounds() - { - $this->original[$this->getLftName()] = null; - $this->original[$this->getRgtName()] = null; - - return $this; - } - - /** - * - * @return $this - */ - protected function assertNotDescendant(self $node) - { - if ($node == $this || $node->isDescendantOf($this)) { - $field = $node->getParentIdName(); - $error = \Illuminate\Validation\ValidationException::withMessages([ - $field => [__('crud.errors.node_must_not_be_a_descendant')] - ]); - throw $error; - //throw new LogicException('Node must not be a descendant.'); - } - - return $this; - } - - /** - * - * @return $this - */ - protected function assertNodeExists(self $node) - { - if (!$node->getLft() || !$node->getRgt()) { - $field = $node->getParentIdName(); - $error = \Illuminate\Validation\ValidationException::withMessages([ - $field => [__('crud.errors.invalid_node')] - ]); - throw $error; - } - - return $this; - } - - /** - */ - protected function assertSameScope(self $node) - { - return; - /*if ( ! $scoped = $this->getScopeAttributes()) { - return; - } - - foreach ($scoped as $attr) { - if ($this->getAttribute($attr) != $node->getAttribute($attr)) { - throw new LogicException('Nodes must be in the same scope'); - } - }*/ - } - - /** - * - * @return \Illuminate\Database\Eloquent\Model - */ - public function replicate(array $except = null) - { - $defaults = [ - $this->getParentIdName(), - $this->getLftName(), - $this->getRgtName(), - ]; - - $except = $except ? array_unique(array_merge($except, $defaults)) : $defaults; - - return parent::replicate($except); - } -} diff --git a/app/Models/Creature.php b/app/Models/Creature.php index 11940b587c..9bda585818 100644 --- a/app/Models/Creature.php +++ b/app/Models/Creature.php @@ -13,6 +13,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\Builder; +use Staudenmeir\LaravelAdjacencyList\Eloquent\HasRecursiveRelationships; /** * Class Creature @@ -32,7 +33,7 @@ class Creature extends MiscModel use CampaignTrait; use ExportableTrait; use HasFactory; - use Nested; + use HasRecursiveRelationships; use SoftDeletes; use SortableTrait; @@ -80,22 +81,11 @@ class Creature extends MiscModel /** * @return string */ - public function getParentIdName() + public function getParentKeyName() { return 'creature_id'; } - - /** - * Specify parent id attribute mutator - * @param int $value - * @throws \Exception - */ - public function setCreatureIdAttribute($value) - { - $this->setParentIdAttribute($value); - } - /** * Performance with for datagrids */ diff --git a/app/Models/Event.php b/app/Models/Event.php index 4a02b87cf8..22794ffe42 100644 --- a/app/Models/Event.php +++ b/app/Models/Event.php @@ -4,7 +4,6 @@ use App\Facades\Module; use App\Models\Concerns\Acl; -use App\Models\Concerns\Nested; use App\Models\Concerns\SortableTrait; use App\Traits\CampaignTrait; use App\Traits\ExportableTrait; @@ -12,6 +11,7 @@ use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Staudenmeir\LaravelAdjacencyList\Eloquent\HasRecursiveRelationships; /** * Class Event @@ -27,13 +27,12 @@ */ class Event extends MiscModel { - use Acl - ; + use Acl; use CalendarDateTrait; use CampaignTrait; use ExportableTrait; use HasFactory; - use Nested; + use HasRecursiveRelationships; use SoftDeletes; use SortableTrait; @@ -57,6 +56,8 @@ class Event extends MiscModel 'event.name', ]; + protected string $entityType = 'event'; + /** * Fields that can be sorted on */ @@ -104,9 +105,7 @@ public function scopePreparedWith(Builder $query): Builder 'event.entity' => function ($sub) { $sub->select('id', 'name', 'entity_id', 'type_id'); }, - 'descendants' => function ($sub) { - $sub->select('id', 'name', 'event_id'); - }, + 'descendants', 'events' => function ($sub) { $sub->select('id', 'name', 'event_id'); }, @@ -125,19 +124,6 @@ public function datagridSelectFields(): array return ['location_id', 'event_id', 'date']; } - /** - * Entity type - */ - protected string $entityType = 'event'; - - /** - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ - public function campaign() - { - return $this->belongsTo('App\Models\Campaign', 'campaign_id', 'id'); - } - /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ @@ -170,23 +156,11 @@ public function entityTypeId(): int return (int) config('entities.ids.event'); } - /** - * @return string - */ - public function getParentIdName() + public function getParentKeyName() { return 'event_id'; } - /** - * Specify parent id attribute mutator - * @param int $value - */ - public function setEventIdAttribute($value) - { - $this->setParentIdAttribute($value); - } - /** */ public function menuItems(array $items = []): array diff --git a/app/Models/Family.php b/app/Models/Family.php index 2a7198099a..f61a2d06a9 100644 --- a/app/Models/Family.php +++ b/app/Models/Family.php @@ -13,6 +13,7 @@ use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Staudenmeir\LaravelAdjacencyList\Eloquent\HasRecursiveRelationships; /** * Class Family @@ -31,7 +32,7 @@ class Family extends MiscModel use CampaignTrait; use ExportableTrait; use HasFactory; - use Nested; + use HasRecursiveRelationships; use SoftDeletes; use SortableTrait; @@ -93,20 +94,11 @@ class Family extends MiscModel * Parent ID used for the Node Trait * @return string */ - public function getParentIdName() + public function getParentKeyName() { return 'family_id'; } - /** - * Specify parent id attribute mutator - * @param int $value - */ - public function setFamilyIdAttribute($value) - { - $this->setParentIdAttribute($value); - } - /** * Performance with for datagrids */ diff --git a/app/Models/Item.php b/app/Models/Item.php index d0b0928e77..357614e7f9 100644 --- a/app/Models/Item.php +++ b/app/Models/Item.php @@ -129,7 +129,7 @@ public function tooltipSubtitle(): string } - public function getParentIdName(): string + public function getParentKeyName(): string { return 'item_id'; } diff --git a/app/Models/Journal.php b/app/Models/Journal.php index 75b78d6082..c92496ddab 100644 --- a/app/Models/Journal.php +++ b/app/Models/Journal.php @@ -12,6 +12,7 @@ use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Builder; +use Staudenmeir\LaravelAdjacencyList\Eloquent\HasRecursiveRelationships; /** * Class Journal @@ -35,7 +36,7 @@ class Journal extends MiscModel use CampaignTrait; use ExportableTrait; use HasFactory; - use Nested; + use HasRecursiveRelationships; use SoftDeletes; use SortableTrait; @@ -216,20 +217,11 @@ public function entityTypeId(): int * Parent ID field for the Node trait * @return string */ - public function getParentIdName() + public function getParentKeyName() { return 'journal_id'; } - /** - * Specify parent id attribute mutator - * @param int $value - */ - public function setJournalIdAttribute($value) - { - $this->setParentIdAttribute($value); - } - /** * Determine if the model has profile data to be displayed */ diff --git a/app/Models/Location.php b/app/Models/Location.php index 6c2a1eda17..efa8e9ceca 100644 --- a/app/Models/Location.php +++ b/app/Models/Location.php @@ -6,13 +6,13 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use App\Facades\Module; use App\Models\Concerns\Acl; -use App\Models\Concerns\Nested; use App\Models\Concerns\SortableTrait; use App\Traits\CampaignTrait; use App\Traits\ExportableTrait; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\Builder; +use Staudenmeir\LaravelAdjacencyList\Eloquent\HasRecursiveRelationships; /** * Class Location @@ -39,7 +39,7 @@ class Location extends MiscModel use CampaignTrait; use ExportableTrait; use HasFactory; - use Nested; + use HasRecursiveRelationships; use SoftDeletes; use SortableTrait; @@ -83,10 +83,7 @@ class Location extends MiscModel 'base', ]; - /** - * @return string - */ - public function getParentIdName() + public function getParentKeyName() { return 'location_id'; } @@ -267,15 +264,6 @@ public function allOrganisations() return Organisation::whereIn('location_id', $locationIds)->with('location'); } - /** - * Specify parent id attribute mutator - * @param int $value - */ - public function setLocationIdAttribute($value) - { - $this->setParentIdAttribute($value); - } - /** * Detach children when moving this entity from one campaign to another */ diff --git a/app/Models/Map.php b/app/Models/Map.php index 6c4c3c7ecb..1b940b46ca 100644 --- a/app/Models/Map.php +++ b/app/Models/Map.php @@ -15,6 +15,7 @@ use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Storage; +use Staudenmeir\LaravelAdjacencyList\Eloquent\HasRecursiveRelationships; /** * Class Ability @@ -49,7 +50,7 @@ class Map extends MiscModel use CampaignTrait; use ExportableTrait; use HasFactory; - use Nested; + use HasRecursiveRelationships; use SoftDeletes; use SortableTrait; @@ -149,19 +150,11 @@ class Map extends MiscModel * Parent ID used for the Node Trait * @return string */ - public function getParentIdName() + public function getParentKeyName() { return 'map_id'; } - /** - * Specify parent id attribute mutator - * @param int $value - */ - public function setMapIdAttribute($value) - { - $this->setParentIdAttribute($value); - } /** * Performance with for datagrids diff --git a/app/Models/MiscModel.php b/app/Models/MiscModel.php index 34018ef98c..dc6284f3fd 100644 --- a/app/Models/MiscModel.php +++ b/app/Models/MiscModel.php @@ -478,8 +478,6 @@ public function ignoredLogAttributes(): array 'campaign_id', 'updated_at', 'deleted_at', - '_lft', - '_rgt', ]; } diff --git a/app/Models/Note.php b/app/Models/Note.php index f7ff85a3e8..589619c927 100644 --- a/app/Models/Note.php +++ b/app/Models/Note.php @@ -10,6 +10,7 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Collection; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Staudenmeir\LaravelAdjacencyList\Eloquent\HasRecursiveRelationships; /** * Class Note @@ -25,7 +26,7 @@ class Note extends MiscModel use CampaignTrait; use ExportableTrait; use HasFactory; - use Nested; + use HasRecursiveRelationships; use SoftDeletes; /** @var string[] */ @@ -121,20 +122,11 @@ public function notes() * Parent ID field for the Node trait * @return string */ - public function getParentIdName() + public function getParentKeyName() { return 'note_id'; } - /** - * Specify parent id attribute mutator - * @param int $value - */ - public function setNoteIdAttribute($value) - { - $this->setParentIdAttribute($value); - } - /** * Define the fields unique to this model that can be used on filters * @return string[] diff --git a/app/Models/Organisation.php b/app/Models/Organisation.php index b0699cfa23..5a6aee4fcb 100644 --- a/app/Models/Organisation.php +++ b/app/Models/Organisation.php @@ -13,6 +13,7 @@ use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Staudenmeir\LaravelAdjacencyList\Eloquent\HasRecursiveRelationships; /** * Class Organisation @@ -32,7 +33,7 @@ class Organisation extends MiscModel use CampaignTrait; use ExportableTrait; use HasFactory; - use Nested; + use HasRecursiveRelationships; use SoftDeletes; use SortableTrait; @@ -106,6 +107,7 @@ public function scopePreparedWith(Builder $query): Builder 'location', 'location.entity', 'organisation', + 'organisation.entity', 'members', 'organisations', 'children' => function ($sub) { @@ -184,21 +186,11 @@ public function organisations() /** * @return string */ - public function getParentIdName() + public function getParentKeyName() { return 'organisation_id'; } - - /** - * Specify parent id attribute mutator - * @param int $value - */ - public function setOrganisationIdAttribute($value) - { - $this->setParentIdAttribute($value); - } - /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ diff --git a/app/Models/Quest.php b/app/Models/Quest.php index f8ad0f9a70..2b1d13abec 100644 --- a/app/Models/Quest.php +++ b/app/Models/Quest.php @@ -13,6 +13,7 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Support\Collection; +use Staudenmeir\LaravelAdjacencyList\Eloquent\HasRecursiveRelationships; /** * Class Quest @@ -35,7 +36,7 @@ class Quest extends MiscModel use CampaignTrait; use ExportableTrait; use HasFactory; - use Nested; + use HasRecursiveRelationships; use SoftDeletes; use SortableTrait; @@ -206,20 +207,11 @@ public function quests() return $this->hasMany(Quest::class); } - /** - * Specify parent id attribute mutator - * @param int $value - */ - public function setQuestIdAttribute($value) - { - $this->setParentIdAttribute($value); - } - /** * Parent ID field for the Node trait * @return string */ - public function getParentIdName() + public function getParentKeyName() { return 'quest_id'; } diff --git a/app/Models/Race.php b/app/Models/Race.php index b801133a5b..ebfe2e6d55 100644 --- a/app/Models/Race.php +++ b/app/Models/Race.php @@ -13,6 +13,7 @@ use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Staudenmeir\LaravelAdjacencyList\Eloquent\HasRecursiveRelationships; /** * Class Race @@ -32,7 +33,7 @@ class Race extends MiscModel use CampaignTrait; use ExportableTrait; use HasFactory; - use Nested; + use HasRecursiveRelationships; use SoftDeletes; use SortableTrait; @@ -80,22 +81,11 @@ class Race extends MiscModel /** * @return string */ - public function getParentIdName() + public function getParentKeyName() { return 'race_id'; } - - /** - * Specify parent id attribute mutator - * @param int $value - * @throws \Exception - */ - public function setRaceIdAttribute($value) - { - $this->setParentIdAttribute($value); - } - /** * Performance with for datagrids */ @@ -108,6 +98,8 @@ public function scopePreparedWith(Builder $query): Builder 'entity.image' => function ($sub) { $sub->select('campaign_id', 'id', 'ext', 'focus_x', 'focus_y'); }, + 'race', + 'race.entity', 'races' => function ($sub) { $sub->select('id', 'name', 'race_id'); }, diff --git a/app/Models/Tag.php b/app/Models/Tag.php index 470673667c..aac9086598 100644 --- a/app/Models/Tag.php +++ b/app/Models/Tag.php @@ -14,6 +14,7 @@ use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Staudenmeir\LaravelAdjacencyList\Eloquent\HasRecursiveRelationships; /** * Class Tag @@ -36,7 +37,7 @@ class Tag extends MiscModel use CampaignTrait; use ExportableTrait; use HasFactory; - use Nested; + use HasRecursiveRelationships; use SoftDeletes; use SortableTrait; use TagScopes; @@ -111,29 +112,12 @@ public function tags() { return $this->hasMany('App\Models\Tag', 'tag_id', 'id'); } - public function children() - { - return $this->tags(); - } - /** - * @return string - */ - public function getParentIdName() + public function getParentKeyName(): string { return 'tag_id'; } - /** - * Specify parent id attribute mutator - * @param int $value - * @throws \Exception - */ - public function setTagIdAttribute($value) - { - $this->setParentIdAttribute($value); - } - /** */ public function scopePreparedWith(Builder $query): Builder @@ -154,9 +138,7 @@ public function scopePreparedWith(Builder $query): Builder 'tags' => function ($sub) { $sub->select('id', 'tag_id', 'name'); }, - 'descendants' => function ($sub) { - $sub->select('id', 'tag_id'); - }, + 'descendants', 'descendants.entities' => function ($sub) { $sub->select('entities.id', 'entities.name', 'entities.entity_id', 'entities.type_id'); }, diff --git a/app/Models/Timeline.php b/app/Models/Timeline.php index f23b18b10f..02e4cca4df 100644 --- a/app/Models/Timeline.php +++ b/app/Models/Timeline.php @@ -8,10 +8,12 @@ use App\Models\Concerns\SortableTrait; use App\Traits\CampaignTrait; use App\Traits\ExportableTrait; +use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Support\Collection; +use Staudenmeir\LaravelAdjacencyList\Eloquent\HasRecursiveRelationships; /** * @property TimelineEra[]|Collection $eras @@ -26,7 +28,7 @@ class Timeline extends MiscModel use CampaignTrait; use ExportableTrait; use HasFactory; - use Nested; + use HasRecursiveRelationships; use SoftDeletes; use SortableTrait; @@ -131,10 +133,7 @@ public function calendar() return $this->belongsTo('App\Models\Calendar', 'calendar_id', 'id'); } - /** - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function timelines() + public function timelines(): HasMany { return $this->hasMany('App\Models\Timeline', 'timeline_id', 'id'); } @@ -147,18 +146,12 @@ public function timeline() return $this->belongsTo('App\Models\Timeline', 'timeline_id', 'id'); } - /** - * - */ - public function eras() + public function eras(): HasMany { return $this->hasMany('App\Models\TimelineEra'); } - /** - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function elements() + public function elements(): HasMany { return $this->hasMany( 'App\Models\TimelineElement', @@ -168,20 +161,11 @@ public function elements() /** * @return string */ - public function getParentIdName() + public function getParentKeyName() { return 'timeline_id'; } - /** - * Specify parent id attribute mutator - * @param int|null $value - */ - public function setTimelineIdAttribute($value) - { - $this->setParentIdAttribute($value); - } - /** */ public function menuItems(array $items = []): array diff --git a/app/Observers/AbilityObserver.php b/app/Observers/AbilityObserver.php index 9d4c801588..760a2e267f 100644 --- a/app/Observers/AbilityObserver.php +++ b/app/Observers/AbilityObserver.php @@ -21,7 +21,5 @@ public function deleting(MiscModel $model) $sub->ability_id = null; $sub->saveQuietly(); } - - $this->cleanupTree($model, 'ability_id'); } } diff --git a/app/Observers/AttributeTemplateObserver.php b/app/Observers/AttributeTemplateObserver.php index eed5a31f49..2434282aba 100644 --- a/app/Observers/AttributeTemplateObserver.php +++ b/app/Observers/AttributeTemplateObserver.php @@ -20,7 +20,5 @@ public function deleting(MiscModel $attributeTemplate) $sub->attribute_template_id = null; $sub->saveQuietly(); } - - $this->cleanupTree($attributeTemplate, 'attribute_template_id'); } } diff --git a/app/Observers/CreatureObserver.php b/app/Observers/CreatureObserver.php index 1026b7977a..17c78c661a 100644 --- a/app/Observers/CreatureObserver.php +++ b/app/Observers/CreatureObserver.php @@ -31,7 +31,5 @@ public function deleting(Creature $creature) $sub->creature_id = null; $sub->saveQuietly(); } - - $this->cleanupTree($creature, 'creature_id'); } } diff --git a/app/Observers/EventObserver.php b/app/Observers/EventObserver.php index 04f8fe2bd7..09828b7522 100644 --- a/app/Observers/EventObserver.php +++ b/app/Observers/EventObserver.php @@ -16,7 +16,5 @@ public function deleting(Event $event) $sub->event_id = null; $sub->saveQuietly(); } - - $this->cleanupTree($event, 'event_id'); } } diff --git a/app/Observers/FamilyObserver.php b/app/Observers/FamilyObserver.php index 7b434327c9..a8a45b1467 100644 --- a/app/Observers/FamilyObserver.php +++ b/app/Observers/FamilyObserver.php @@ -73,7 +73,5 @@ public function deleting(Family $family) $sub->family_id = null; $sub->saveQuietly(); } - - $this->cleanupTree($family, 'family_id'); } } diff --git a/app/Observers/JournalObserver.php b/app/Observers/JournalObserver.php index b3a35c7adb..0ef1f71e93 100644 --- a/app/Observers/JournalObserver.php +++ b/app/Observers/JournalObserver.php @@ -20,7 +20,5 @@ public function deleting(MiscModel $journal) $sub->journal_id = null; $sub->saveQuietly(); } - - $this->cleanupTree($journal, 'journal_id'); } } diff --git a/app/Observers/LocationObserver.php b/app/Observers/LocationObserver.php index d6fba3a8ca..1754fa1dc9 100644 --- a/app/Observers/LocationObserver.php +++ b/app/Observers/LocationObserver.php @@ -19,8 +19,6 @@ public function deleting(Location $location) $sub->location_id = null; $sub->saveQuietly(); } - - $this->cleanupTree($location, 'location_id'); } /** diff --git a/app/Observers/MapObserver.php b/app/Observers/MapObserver.php index f2f4c48523..67d2db062f 100644 --- a/app/Observers/MapObserver.php +++ b/app/Observers/MapObserver.php @@ -39,8 +39,6 @@ public function deleting(MiscModel $model) $sub->map_id = null; $sub->saveQuietly(); } - - $this->cleanupTree($model, 'map_id'); } /** diff --git a/app/Observers/MiscObserver.php b/app/Observers/MiscObserver.php index 1be6dc50f0..02a96bef47 100644 --- a/app/Observers/MiscObserver.php +++ b/app/Observers/MiscObserver.php @@ -165,35 +165,4 @@ protected function syncMentions(MiscModel $model, Entity $entity) $this->entityMappingService->silent()->mapEntity($entity); } } - - - - /** - * @param MiscModel|Location $model - */ - protected function cleanupTree(MiscModel $model, string $field = 'parent_id') - { - // Warning: we probably don't need this anymore, since we've removed the deleted() listened - // in the Nested trait. - - // We need to refresh our foreign relations to avoid deleting our children nodes again - $model->refresh(); - - // Check that we have no descendants anymore. - /** @var Location $model */ - if ($model->descendants()->count() === 0) { - return; - } - - foreach ($model->descendants as $sub) { - if (!empty($sub->$field)) { - continue; - } - - // Got a descendant with the parent id null. Let's get them out of the tree - $sub->{$sub->getLftName()} = null; - $sub->{$sub->getRgtName()} = null; - $sub->save(); - } - } } diff --git a/app/Observers/NoteObserver.php b/app/Observers/NoteObserver.php index d5c3ef1356..1cd2c9580f 100644 --- a/app/Observers/NoteObserver.php +++ b/app/Observers/NoteObserver.php @@ -20,7 +20,5 @@ public function deleting(MiscModel $note) $sub->note_id = null; $sub->saveQuietly(); } - - $this->cleanupTree($note, 'note_id'); } } diff --git a/app/Observers/OrganisationObserver.php b/app/Observers/OrganisationObserver.php index 5dc40a60f9..843b062a4b 100644 --- a/app/Observers/OrganisationObserver.php +++ b/app/Observers/OrganisationObserver.php @@ -30,11 +30,8 @@ public function deleting(Organisation $organisation) */ foreach ($organisation->organisations as $child) { $child->organisation_id = null; - $child->save(); + $child->saveQuietly(); } - - // We need to refresh our foreign relations to avoid deleting our children nodes again - $this->cleanupTree($organisation, 'organisation_id'); } /** diff --git a/app/Observers/RaceObserver.php b/app/Observers/RaceObserver.php index 691cbe9329..f7e5949c89 100644 --- a/app/Observers/RaceObserver.php +++ b/app/Observers/RaceObserver.php @@ -33,7 +33,5 @@ public function deleting(Race $race) $sub->race_id = null; $sub->saveQuietly(); } - - $this->cleanupTree($race, 'race_id'); } } diff --git a/app/Observers/TagObserver.php b/app/Observers/TagObserver.php index 1a9fd989a9..9d70c2a2f4 100644 --- a/app/Observers/TagObserver.php +++ b/app/Observers/TagObserver.php @@ -13,9 +13,7 @@ public function deleting(Tag $model) // Update sub tags to clean them up foreach ($model->tags as $child) { $child->tag_id = null; - $child->save(); + $child->saveQuietly(); } - - $this->cleanupTree($model, 'tag_id'); } } diff --git a/app/Observers/TimelineObserver.php b/app/Observers/TimelineObserver.php index 3b206d0726..461dfe9d4f 100644 --- a/app/Observers/TimelineObserver.php +++ b/app/Observers/TimelineObserver.php @@ -53,7 +53,5 @@ public function deleting(MiscModel $timeline) $sub->timeline_id = null; $sub->saveQuietly(); } - - $this->cleanupTree($timeline, 'timeline_id'); } } diff --git a/app/Services/Campaign/Import/ImportService.php b/app/Services/Campaign/Import/ImportService.php index c89ba74460..aa1034280f 100644 --- a/app/Services/Campaign/Import/ImportService.php +++ b/app/Services/Campaign/Import/ImportService.php @@ -265,7 +265,7 @@ protected function entities(): self unset($data); } $this->logs[] = $count; - $mapper->tree()->fixTree()->clear(); + $mapper->tree()->clear(); } // Second parse diff --git a/app/Services/Campaign/Import/Mappers/EntityMapper.php b/app/Services/Campaign/Import/Mappers/EntityMapper.php index c4597d9bd0..5077fe6171 100644 --- a/app/Services/Campaign/Import/Mappers/EntityMapper.php +++ b/app/Services/Campaign/Import/Mappers/EntityMapper.php @@ -495,15 +495,4 @@ protected function foreignMentions(): self } return $this; } - - public function fixTree(): self - { - $base = app()->make($this->className); - if (!method_exists($base, 'recalculateTreeBounds')) { - return $this; - } - // @phpstan-ignore-next-line - $base->fixCampaignTree($this->campaign->id); - return $this; - } } diff --git a/app/Services/Entity/EntityRelationService.php b/app/Services/Entity/EntityRelationService.php index 698b685ada..41ffffe8aa 100644 --- a/app/Services/Entity/EntityRelationService.php +++ b/app/Services/Entity/EntityRelationService.php @@ -669,7 +669,7 @@ protected function addLocation(): self */ protected function addParent() { - if (!method_exists($this->entity->child, 'getParentIdName')) { + if (!method_exists($this->entity->child, 'getParentKeyName')) { // If not part of the node model, check for the {self}_id attribute // @phpstan-ignore-next-line if (!array_key_exists($this->entity->type() . '_id', $this->entity->child->getAttributes())) { diff --git a/app/Services/Entity/MoveService.php b/app/Services/Entity/MoveService.php index b2a9788168..a2c2bf23e9 100644 --- a/app/Services/Entity/MoveService.php +++ b/app/Services/Entity/MoveService.php @@ -13,7 +13,6 @@ use App\Models\Timeline; use App\Models\TimelineEra; use App\Traits\CampaignAware; -use App\Traits\CanFixTree; use App\Traits\EntityAware; use App\Traits\UserAware; use Illuminate\Support\Facades\DB; @@ -24,7 +23,6 @@ class MoveService { use CampaignAware; - use CanFixTree; use EntityAware; use UserAware; @@ -113,7 +111,6 @@ protected function copyEntity(): bool } CampaignLocalization::forceCampaign($this->to); - $this->fixTree($newModel); // The model is ready to be saved. $newModel->saveQuietly(); @@ -216,7 +213,6 @@ protected function moveEntity(): bool } $this->entity->saveQuietly(); - $this->fixTree($child); // Update child second. We do this otherwise we'll have an old entity and a new one $child->campaign_id = $this->to->id; if (empty($child->slug)) { diff --git a/app/Services/Entity/TransformService.php b/app/Services/Entity/TransformService.php index 1223ca82be..282ea65cc0 100644 --- a/app/Services/Entity/TransformService.php +++ b/app/Services/Entity/TransformService.php @@ -6,19 +6,14 @@ use App\Models\Character; use App\Models\Entity; use App\Models\Post; -use App\Models\Family; -use App\Models\Location; use App\Models\MiscModel; -use App\Models\Organisation; use App\Models\OrganisationMember; -use App\Traits\CanFixTree; use App\Traits\EntityAware; use Illuminate\Support\Str; use Exception; class TransformService { - use CanFixTree; use EntityAware; protected MiscModel $child; @@ -46,8 +41,6 @@ public function transform(string $target): Entity ->removePosts() ; - $this->fixTree($this->new); - // Finally, we can save. Should be all good. $this->new->campaign_id = $this->child->campaign_id; $this->new->saveQuietly(); diff --git a/app/Services/RecoveryService.php b/app/Services/RecoveryService.php index d6d321284a..1b1ce99630 100644 --- a/app/Services/RecoveryService.php +++ b/app/Services/RecoveryService.php @@ -127,8 +127,8 @@ protected function trashChild(Entity $entity, MiscModel $child = null) \App\Facades\CampaignLocalization::setConsoleCampaign($entity->campaign_id); // Update the parent_id / tree before - if (method_exists($child, 'getParentIdName')) { - $parentField = $child->getParentIdName(); + if (method_exists($child, 'getParentKeyName')) { + $parentField = $child->getParentKeyName(); // Detach children of this entity. Usually this is already done in the model observer, because // if the parent is deleted in a node, the children aren't available. @@ -151,11 +151,6 @@ protected function trashChild(Entity $entity, MiscModel $child = null) // Clean up the parent and tree to avoid the nested plugin to delete every child $child->$parentField = null; - if (method_exists($child, 'getRgtName')) { - $child->_lft = null; // @phpstan-ignore-line - $child->_rgt = null; // @phpstan-ignore-line - } - $child->timestamps = false; $child->saveQuietly(); $child->refresh(); @@ -173,7 +168,6 @@ protected function trashChild(Entity $entity, MiscModel $child = null) $child->forceDelete(); - // Unset the campaign id limitation again \App\Facades\CampaignLocalization::setConsoleCampaign(0); diff --git a/app/Traits/CanFixTree.php b/app/Traits/CanFixTree.php deleted file mode 100644 index 15f975592e..0000000000 --- a/app/Traits/CanFixTree.php +++ /dev/null @@ -1,45 +0,0 @@ -{$model->getParentIdName()} = null; - } - return; - } - $isLocationWithParent = in_array('location_id', $model->getFillable()) && !empty($model->getParentId()); - // If it's not a location or the parent location is empty, force the parent to be properly empty - if (!$isLocationWithParent) { - /** @var Location $model */ - $model->setParentId(null); - } - $model->{$model->getRgtName()} = 0; - $model->{$model->getLftName()} = 0; - if ($model->exists) { - $model->exists = false; - $model->recalculateTreeBounds(); - $model->exists = true; - } else { - $model->recalculateTreeBounds(); - } - // For a location with a parent, place it inside the tree - if ($isLocationWithParent) { - $model->forcePendingAction(); - } - } -} diff --git a/app/Traits/ExportableTrait.php b/app/Traits/ExportableTrait.php index e554d95a75..bbec4d54d3 100644 --- a/app/Traits/ExportableTrait.php +++ b/app/Traits/ExportableTrait.php @@ -47,8 +47,8 @@ protected function baseExportData(): self $this->exportData[$baseField] = $this->$baseField; } } - if (method_exists($this, 'getParentIdName')) { - $this->exportData[$this->getParentIdName()] = $this->getAttribute($this->getParentIdName()); + if (method_exists($this, 'getParentKeyName')) { + $this->exportData[$this->getParentKeyName()] = $this->getAttribute($this->getParentKeyName()); } return $this; diff --git a/app/Traits/TreeControllerTrait.php b/app/Traits/TreeControllerTrait.php index bf97f4fd31..18453a6a77 100644 --- a/app/Traits/TreeControllerTrait.php +++ b/app/Traits/TreeControllerTrait.php @@ -70,7 +70,7 @@ public function tree(Request $request, Campaign $campaign) ->distinct(); /** @var Tag $model **/ - $parentKey = $model->getParentIdName(); + $parentKey = $model->getParentKeyName(); $parent = null; if (request()->has('parent_id')) { $base->where([$model->getTable() . '.' . $parentKey => request()->get('parent_id')]); diff --git a/composer.json b/composer.json index a236df48a7..d4b73d8049 100644 --- a/composer.json +++ b/composer.json @@ -43,6 +43,8 @@ "sergej-kurakin/diceroller": "^2.0", "spatie/laravel-backup": "^8.0", "srmklive/paypal": "^3.0", + "staudenmeir/laravel-adjacency-list": "^1.0", + "staudenmeir/laravel-cte": "^1.0", "stechstudio/laravel-zipstream": "^4.13", "stevebauman/purify": "5.1.*", "symfony/http-client": "^6.2", diff --git a/composer.lock b/composer.lock index e4ee4f72af..1e92137cc0 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "a8633acb841bbc3315fac40289477004", + "content-hash": "9920ed83b12c85baa70f8510ca1130cc", "packages": [ { "name": "aws/aws-crt-php", @@ -7895,6 +7895,169 @@ }, "time": "2023-11-09T22:02:55+00:00" }, + { + "name": "staudenmeir/eloquent-has-many-deep-contracts", + "version": "v1.1", + "source": { + "type": "git", + "url": "https://github.com/staudenmeir/eloquent-has-many-deep-contracts.git", + "reference": "c39317b839d6123be126b9980e4a3d38310f5939" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/staudenmeir/eloquent-has-many-deep-contracts/zipball/c39317b839d6123be126b9980e4a3d38310f5939", + "reference": "c39317b839d6123be126b9980e4a3d38310f5939", + "shasum": "" + }, + "require": { + "illuminate/database": "^10.0", + "php": "^8.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Staudenmeir\\EloquentHasManyDeepContracts\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonas Staudenmeir", + "email": "mail@jonas-staudenmeir.de" + } + ], + "description": "Contracts for staudenmeir/eloquent-has-many-deep", + "support": { + "issues": "https://github.com/staudenmeir/eloquent-has-many-deep-contracts/issues", + "source": "https://github.com/staudenmeir/eloquent-has-many-deep-contracts/tree/v1.1" + }, + "time": "2023-01-18T12:43:26+00:00" + }, + { + "name": "staudenmeir/laravel-adjacency-list", + "version": "v1.14", + "source": { + "type": "git", + "url": "https://github.com/staudenmeir/laravel-adjacency-list.git", + "reference": "051f35cf6a54c8950fb0669b71c1ea2943a25af2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/staudenmeir/laravel-adjacency-list/zipball/051f35cf6a54c8950fb0669b71c1ea2943a25af2", + "reference": "051f35cf6a54c8950fb0669b71c1ea2943a25af2", + "shasum": "" + }, + "require": { + "illuminate/database": "^10.0", + "php": "^8.1", + "staudenmeir/eloquent-has-many-deep-contracts": "^1.1", + "staudenmeir/laravel-cte": "^1.8" + }, + "require-dev": { + "barryvdh/laravel-ide-helper": "^2.13", + "doctrine/dbal": "^3.5.2", + "mockery/mockery": "^1.5.1", + "nunomaduro/larastan": "^2.0", + "orchestra/testbench": "^8.15", + "phpunit/phpunit": "^10.1", + "singlestoredb/singlestoredb-laravel": "^1.5.1", + "staudenmeir/eloquent-has-many-deep": "^1.18.1" + }, + "suggest": { + "barryvdh/laravel-ide-helper": "Provide type hints for attributes and relations." + }, + "type": "library", + "autoload": { + "psr-4": { + "Staudenmeir\\LaravelAdjacencyList\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonas Staudenmeir", + "email": "mail@jonas-staudenmeir.de" + } + ], + "description": "Recursive Laravel Eloquent relationships with CTEs", + "support": { + "issues": "https://github.com/staudenmeir/laravel-adjacency-list/issues", + "source": "https://github.com/staudenmeir/laravel-adjacency-list/tree/v1.14" + }, + "funding": [ + { + "url": "https://paypal.me/JonasStaudenmeir", + "type": "custom" + } + ], + "time": "2023-11-30T13:36:43+00:00" + }, + { + "name": "staudenmeir/laravel-cte", + "version": "v1.9", + "source": { + "type": "git", + "url": "https://github.com/staudenmeir/laravel-cte.git", + "reference": "87f4447829a0f6a6268f52f875c468915cab4909" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/staudenmeir/laravel-cte/zipball/87f4447829a0f6a6268f52f875c468915cab4909", + "reference": "87f4447829a0f6a6268f52f875c468915cab4909", + "shasum": "" + }, + "require": { + "illuminate/database": "^10.0", + "php": "^8.1" + }, + "require-dev": { + "orchestra/testbench": "^8.0", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.1", + "singlestoredb/singlestoredb-laravel": "^1.5.1" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Staudenmeir\\LaravelCte\\DatabaseServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Staudenmeir\\LaravelCte\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonas Staudenmeir", + "email": "mail@jonas-staudenmeir.de" + } + ], + "description": "Laravel queries with common table expressions", + "support": { + "issues": "https://github.com/staudenmeir/laravel-cte/issues", + "source": "https://github.com/staudenmeir/laravel-cte/tree/v1.9" + }, + "funding": [ + { + "url": "https://paypal.me/JonasStaudenmeir", + "type": "custom" + } + ], + "time": "2023-09-01T17:22:23+00:00" + }, { "name": "stechstudio/laravel-zipstream", "version": "4.13", diff --git a/database/migrations/2023_12_02_154727_remove_old_trees.php b/database/migrations/2023_12_02_154727_remove_old_trees.php new file mode 100644 index 0000000000..270ca9cea9 --- /dev/null +++ b/database/migrations/2023_12_02_154727_remove_old_trees.php @@ -0,0 +1,51 @@ +dropColumn('_lft'); + $table->dropColumn('_rgt'); + }); + } + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // + } +}; From 6340a9f3d6388f9e2e4950bfab0216c3e877a5af Mon Sep 17 00:00:00 2001 From: ilestis Date: Sat, 2 Dec 2023 15:51:37 +0000 Subject: [PATCH 2/5] Fix styling --- app/Console/Commands/InstallCommand.php | 2 +- app/Models/Ability.php | 1 - app/Models/AttributeTemplate.php | 1 - app/Models/Creature.php | 1 - app/Models/Family.php | 1 - app/Models/Journal.php | 1 - app/Models/Map.php | 1 - app/Models/Note.php | 1 - app/Models/Organisation.php | 1 - app/Models/Quest.php | 1 - app/Models/Race.php | 1 - app/Models/Tag.php | 1 - app/Models/Timeline.php | 1 - app/Observers/MiscObserver.php | 1 - database/migrations/2023_12_02_154727_remove_old_trees.php | 5 ++--- 15 files changed, 3 insertions(+), 17 deletions(-) diff --git a/app/Console/Commands/InstallCommand.php b/app/Console/Commands/InstallCommand.php index 074d7ed7fe..0bc03d3eff 100644 --- a/app/Console/Commands/InstallCommand.php +++ b/app/Console/Commands/InstallCommand.php @@ -33,7 +33,7 @@ public function handle() return; } } catch (Exception) { - // + } $this->call('key:generate'); $this->call('migrate'); diff --git a/app/Models/Ability.php b/app/Models/Ability.php index 82f59c1518..67c65ef2ce 100644 --- a/app/Models/Ability.php +++ b/app/Models/Ability.php @@ -5,7 +5,6 @@ use App\Facades\Mentions; use App\Facades\Module; use App\Models\Concerns\Acl; -use App\Models\Concerns\Nested; use App\Models\Concerns\SortableTrait; use App\Traits\CampaignTrait; use App\Traits\ExportableTrait; diff --git a/app/Models/AttributeTemplate.php b/app/Models/AttributeTemplate.php index 9f7edbf859..378d8450d3 100644 --- a/app/Models/AttributeTemplate.php +++ b/app/Models/AttributeTemplate.php @@ -3,7 +3,6 @@ namespace App\Models; use App\Models\Concerns\Acl; -use App\Models\Concerns\Nested; use App\Services\Attributes\RandomService; use App\Traits\CampaignTrait; use Illuminate\Database\Eloquent\Builder; diff --git a/app/Models/Creature.php b/app/Models/Creature.php index 9bda585818..c4cd63b452 100644 --- a/app/Models/Creature.php +++ b/app/Models/Creature.php @@ -5,7 +5,6 @@ use App\Enums\FilterOption; use App\Facades\Module; use App\Models\Concerns\Acl; -use App\Models\Concerns\Nested; use App\Models\Concerns\SortableTrait; use App\Traits\CampaignTrait; use App\Traits\ExportableTrait; diff --git a/app/Models/Family.php b/app/Models/Family.php index f61a2d06a9..8c25b01106 100644 --- a/app/Models/Family.php +++ b/app/Models/Family.php @@ -5,7 +5,6 @@ use App\Enums\FilterOption; use App\Facades\Module; use App\Models\Concerns\Acl; -use App\Models\Concerns\Nested; use App\Models\Concerns\SortableTrait; use App\Traits\CampaignTrait; use App\Traits\ExportableTrait; diff --git a/app/Models/Journal.php b/app/Models/Journal.php index c92496ddab..c2c1d9b772 100644 --- a/app/Models/Journal.php +++ b/app/Models/Journal.php @@ -4,7 +4,6 @@ use App\Facades\Module; use App\Models\Concerns\Acl; -use App\Models\Concerns\Nested; use App\Models\Concerns\SortableTrait; use App\Traits\CalendarDateTrait; use App\Traits\CampaignTrait; diff --git a/app/Models/Map.php b/app/Models/Map.php index 1b940b46ca..28d0806bc8 100644 --- a/app/Models/Map.php +++ b/app/Models/Map.php @@ -5,7 +5,6 @@ use App\Facades\CampaignLocalization; use App\Facades\Module; use App\Models\Concerns\Acl; -use App\Models\Concerns\Nested; use App\Models\Concerns\SortableTrait; use App\Traits\CampaignTrait; use App\Traits\ExportableTrait; diff --git a/app/Models/Note.php b/app/Models/Note.php index 589619c927..8e04a5355e 100644 --- a/app/Models/Note.php +++ b/app/Models/Note.php @@ -3,7 +3,6 @@ namespace App\Models; use App\Models\Concerns\Acl; -use App\Models\Concerns\Nested; use App\Traits\CampaignTrait; use App\Traits\ExportableTrait; use Illuminate\Database\Eloquent\SoftDeletes; diff --git a/app/Models/Organisation.php b/app/Models/Organisation.php index 5a6aee4fcb..11b30a07aa 100644 --- a/app/Models/Organisation.php +++ b/app/Models/Organisation.php @@ -5,7 +5,6 @@ use App\Enums\FilterOption; use App\Facades\Module; use App\Models\Concerns\Acl; -use App\Models\Concerns\Nested; use App\Models\Concerns\SortableTrait; use App\Traits\CampaignTrait; use App\Traits\ExportableTrait; diff --git a/app/Models/Quest.php b/app/Models/Quest.php index 2b1d13abec..9db728ac1d 100644 --- a/app/Models/Quest.php +++ b/app/Models/Quest.php @@ -4,7 +4,6 @@ use App\Enums\FilterOption; use App\Models\Concerns\Acl; -use App\Models\Concerns\Nested; use App\Models\Concerns\SortableTrait; use App\Traits\CalendarDateTrait; use App\Traits\CampaignTrait; diff --git a/app/Models/Race.php b/app/Models/Race.php index ebfe2e6d55..3873d4f317 100644 --- a/app/Models/Race.php +++ b/app/Models/Race.php @@ -5,7 +5,6 @@ use App\Enums\FilterOption; use App\Facades\Module; use App\Models\Concerns\Acl; -use App\Models\Concerns\Nested; use App\Models\Concerns\SortableTrait; use App\Traits\CampaignTrait; use App\Traits\ExportableTrait; diff --git a/app/Models/Tag.php b/app/Models/Tag.php index aac9086598..af63ed6920 100644 --- a/app/Models/Tag.php +++ b/app/Models/Tag.php @@ -4,7 +4,6 @@ use App\Facades\Module; use App\Models\Concerns\Acl; -use App\Models\Concerns\Nested; use App\Models\Concerns\SortableTrait; use App\Models\Scopes\TagScopes; use App\Traits\CampaignTrait; diff --git a/app/Models/Timeline.php b/app/Models/Timeline.php index 02e4cca4df..fe06cda927 100644 --- a/app/Models/Timeline.php +++ b/app/Models/Timeline.php @@ -4,7 +4,6 @@ use App\Facades\Module; use App\Models\Concerns\Acl; -use App\Models\Concerns\Nested; use App\Models\Concerns\SortableTrait; use App\Traits\CampaignTrait; use App\Traits\ExportableTrait; diff --git a/app/Observers/MiscObserver.php b/app/Observers/MiscObserver.php index 02a96bef47..ba451f6ca4 100644 --- a/app/Observers/MiscObserver.php +++ b/app/Observers/MiscObserver.php @@ -6,7 +6,6 @@ use App\Facades\EntityCache; use App\Facades\Mentions; use App\Models\Entity; -use App\Models\Location; use App\Models\MiscModel; use App\Observers\Concerns\Copiable; use App\Services\Entity\LogService; diff --git a/database/migrations/2023_12_02_154727_remove_old_trees.php b/database/migrations/2023_12_02_154727_remove_old_trees.php index 270ca9cea9..ff4e0ce657 100644 --- a/database/migrations/2023_12_02_154727_remove_old_trees.php +++ b/database/migrations/2023_12_02_154727_remove_old_trees.php @@ -4,8 +4,7 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -return new class extends Migration -{ +return new class () extends Migration { /** * Run the migrations. */ @@ -46,6 +45,6 @@ public function up(): void */ public function down(): void { - // + } }; From ba91172c0128e900ac52b3d1797b7fc92f6f0df8 Mon Sep 17 00:00:00 2001 From: ilestis Date: Sat, 2 Dec 2023 10:17:37 -0600 Subject: [PATCH 3/5] Fix tests and api perfs --- app/Http/Resources/EntityAssetResource.php | 2 +- app/Http/Resources/EntityResource.php | 2 +- app/Http/Resources/InventoryResource.php | 2 +- app/Http/Resources/PostResource.php | 2 +- app/Models/Calendar.php | 2 ++ app/Models/Relations/CalendarRelations.php | 8 -------- app/Models/Scopes/SubEntityScopes.php | 12 +++++++---- tests/TestCase.php | 23 ++++++++++++++-------- 8 files changed, 29 insertions(+), 24 deletions(-) diff --git a/app/Http/Resources/EntityAssetResource.php b/app/Http/Resources/EntityAssetResource.php index 5f00d810ff..15201573eb 100644 --- a/app/Http/Resources/EntityAssetResource.php +++ b/app/Http/Resources/EntityAssetResource.php @@ -17,7 +17,7 @@ public function toArray($request) /** @var EntityAsset $asset */ $asset = $this->resource; - $data = $this->entity([ + $data = $this->onEntity([ 'type_id' => $asset->type_id, '_file' => $asset->isFile(), '_link' => $asset->isLink(), diff --git a/app/Http/Resources/EntityResource.php b/app/Http/Resources/EntityResource.php index 1956ab8c50..e5fea0a291 100644 --- a/app/Http/Resources/EntityResource.php +++ b/app/Http/Resources/EntityResource.php @@ -205,7 +205,7 @@ public function entity(array $prepared = []) if ($misc->ancestors) { $ancestors = []; - foreach ($misc->getAncestors(['id']) as $ancestor) { + foreach ($misc->ancestors as $ancestor) { $ancestors[] = $ancestor->id; } $merged['parents'] = $ancestors; diff --git a/app/Http/Resources/InventoryResource.php b/app/Http/Resources/InventoryResource.php index 99d1fbafaf..3a13b274bd 100644 --- a/app/Http/Resources/InventoryResource.php +++ b/app/Http/Resources/InventoryResource.php @@ -16,7 +16,7 @@ public function toArray($request) { /** @var Inventory $model */ $model = $this->resource; - return $this->entity([ + return $this->onEntity([ 'item_id' => $model->item_id, 'name' => $model->name, 'position' => $model->position, diff --git a/app/Http/Resources/PostResource.php b/app/Http/Resources/PostResource.php index 489138a341..7b415a1a79 100644 --- a/app/Http/Resources/PostResource.php +++ b/app/Http/Resources/PostResource.php @@ -16,7 +16,7 @@ public function toArray($request) { /** @var Post $model */ $model = $this->resource; - return $this->entity([ + return $this->onEntity([ 'name' => $model->name, 'visibility_id' => (int) $model->visibility_id->value, 'entry' => $model->entry, diff --git a/app/Models/Calendar.php b/app/Models/Calendar.php index 3fc5d261fc..0983d9d018 100644 --- a/app/Models/Calendar.php +++ b/app/Models/Calendar.php @@ -12,6 +12,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Support\Arr; use Illuminate\Support\Str; +use Staudenmeir\LaravelAdjacencyList\Eloquent\HasRecursiveRelationships; /** * Class Calendar @@ -40,6 +41,7 @@ class Calendar extends MiscModel use CalendarRelations; use CampaignTrait; use ExportableTrait; + use HasRecursiveRelationships; use HasFactory; use SoftDeletes; diff --git a/app/Models/Relations/CalendarRelations.php b/app/Models/Relations/CalendarRelations.php index 6b8e8a7403..3c46dbdaa1 100644 --- a/app/Models/Relations/CalendarRelations.php +++ b/app/Models/Relations/CalendarRelations.php @@ -44,12 +44,4 @@ public function calendars() { return $this->hasMany(Calendar::class); } - - /** - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function children() - { - return $this->hasMany(Calendar::class); - } } diff --git a/app/Models/Scopes/SubEntityScopes.php b/app/Models/Scopes/SubEntityScopes.php index 1ade3a5e49..09312ecbcd 100644 --- a/app/Models/Scopes/SubEntityScopes.php +++ b/app/Models/Scopes/SubEntityScopes.php @@ -75,14 +75,18 @@ public function scopeWithApi(Builder $query): Builder { $relations = [ 'entity', - 'entity.tags', 'entity.posts', 'entity.events', - 'entity.relationships', 'entity.attributes', 'entity.inventories', + 'entity.tags', + 'entity.posts', 'entity.posts.permissions', + 'entity.events', + 'entity.relationships', 'entity.attributes', 'entity.inventories', 'entity.inventories', 'entity.assets', 'entity.abilities', - 'ancestors', - 'children', ]; + if (method_exists($this, 'ancestors')) { + $relations[] = 'ancestors'; + $relations[] = 'children'; + } $with = !empty($this->apiWith) ? $this->apiWith : []; foreach ($with as $relation) { $relations[] = $relation; diff --git a/tests/TestCase.php b/tests/TestCase.php index 3b947edc94..6869bc77ad 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -12,6 +12,7 @@ use App\Models\Attribute; use App\Models\Bookmark; use App\Models\Campaign; +use App\Services\Permissions\RolePermissionService; use Illuminate\Support\Facades\Storage; use App\Models\CampaignRoleUser; use App\Models\CampaignUser; @@ -120,10 +121,12 @@ public function asPlayer(): self 'user_id' => $user2->id, ]); Permissions::reset(); - CampaignRole::where('id', 3)->first()->toggle(1, 1); - CampaignRole::where('id', 3)->first()->toggle(10, 1); - CampaignRole::where('id', 3)->first()->toggle(11, 1); - CampaignRole::where('id', 3)->first()->toggle(7, 1); + /** @var RolePermissionService $service */ + $service = app()->make(RolePermissionService::class); + $service->role(CampaignRole::where('id', 3)->first())->toggle(1, 1); + $service->role(CampaignRole::where('id', 3)->first())->toggle(10, 1); + $service->role(CampaignRole::where('id', 3)->first())->toggle(11, 1); + $service->role(CampaignRole::where('id', 3)->first())->toggle(7, 1); return $this; } @@ -142,7 +145,9 @@ public function withMember(): self 'user_id' => $user3->id, ]); - CampaignRole::where('id', 3)->first()->toggle(1, 1); + /** @var RolePermissionService $service */ + $service = app()->make(RolePermissionService::class); + $service->role(CampaignRole::where('id', 3)->first())->toggle(1, 1); return $this; } @@ -176,9 +181,11 @@ public function withCampaigns(array $extra = []): self public function withPermissions(array $extra = []): self { - CampaignRole::where('id', 3)->first()->toggle(1, 1); - CampaignRole::where('id', 3)->first()->toggle(1, 2); - CampaignRole::where('id', 3)->first()->toggle(1, 3); + /** @var RolePermissionService $service */ + $service = app()->make(RolePermissionService::class); + $service->role(CampaignRole::where('id', 3)->first())->toggle(1, 1); + $service->role(CampaignRole::where('id', 3)->first())->toggle(1, 2); + $service->role(CampaignRole::where('id', 3)->first())->toggle(1, 3); return $this; } From d46674c3a438588e06a9e77e428beabce6602241 Mon Sep 17 00:00:00 2001 From: ilestis Date: Sat, 2 Dec 2023 16:18:28 +0000 Subject: [PATCH 4/5] Fix styling --- app/Models/Calendar.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Models/Calendar.php b/app/Models/Calendar.php index 0983d9d018..897ebd16b7 100644 --- a/app/Models/Calendar.php +++ b/app/Models/Calendar.php @@ -41,8 +41,8 @@ class Calendar extends MiscModel use CalendarRelations; use CampaignTrait; use ExportableTrait; - use HasRecursiveRelationships; use HasFactory; + use HasRecursiveRelationships; use SoftDeletes; /** @var string[] */ From 65059634eb85324f45c969ccb3ed071bea1be17e Mon Sep 17 00:00:00 2001 From: ilestis Date: Sat, 2 Dec 2023 10:24:16 -0600 Subject: [PATCH 5/5] Fix tests and api perfs --- tests/Feature/Entities/TimelineElementTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Feature/Entities/TimelineElementTest.php b/tests/Feature/Entities/TimelineElementTest.php index 0eab2af4cf..bce32da308 100644 --- a/tests/Feature/Entities/TimelineElementTest.php +++ b/tests/Feature/Entities/TimelineElementTest.php @@ -16,6 +16,7 @@ ->postJson('/api/1.0/campaigns/1/timelines/1/timeline_elements', [ 'name' => fake()->name(), 'era_id' => 1, + 'entry' => '', 'use_event_date' => true, ]) ->assertStatus(201)