feat: synonyms rework (#1109)

This commit is contained in:
Kyrch
2026-02-18 20:26:46 -03:00
committed by GitHub
parent e4179cf312
commit b66c5cb3da
155 changed files with 2021 additions and 1269 deletions
@@ -5,7 +5,7 @@ declare(strict_types=1);
namespace App\Actions\Models\User\Submission\Anime;
use App\Actions\Models\User\Submission\SubmissionAction;
use App\Concerns\Models\CanCreateAnimeSynonym;
use App\Concerns\Models\CanCreateSynonym;
use App\Filament\Resources\Wiki\Song\RelationManagers\PerformanceSongRelationManager;
use App\Models\User\Submission\SubmissionStage;
use App\Models\Wiki\Anime;
@@ -16,7 +16,7 @@ use Illuminate\Support\Facades\DB;
class ManageAnimeSubmissionAction extends SubmissionAction
{
use CanCreateAnimeSynonym;
use CanCreateSynonym;
/**
* Approve the submission stage.
@@ -47,7 +47,7 @@ class ManageAnimeSubmissionAction extends SubmissionAction
protected function createSynonyms(array $synonyms, Anime $anime): void
{
foreach ($synonyms as $synonym) {
$this->createAnimeSynonym(
$this->createSynonym(
Arr::get($synonym, 'text'),
Arr::get($synonym, 'type'),
$anime
@@ -11,14 +11,15 @@ use App\Actions\Models\Wiki\Anime\ExternalApi\AniZipAnimeExternalApiAction;
use App\Actions\Models\Wiki\Anime\ExternalApi\JikanAnimeExternalApiAction;
use App\Actions\Models\Wiki\Anime\ExternalApi\LivechartAnimeExternalApiAction;
use App\Actions\Models\Wiki\Anime\ExternalApi\MalAnimeExternalApiAction;
use App\Concerns\Models\CanCreateAnimeSynonym;
use App\Concerns\Models\CanCreateStudio;
use App\Concerns\Models\CanCreateSynonym;
use App\Concerns\Models\HasLabel;
use App\Contracts\Actions\Models\Wiki\BackfillImages;
use App\Contracts\Actions\Models\Wiki\BackfillResources;
use App\Contracts\Actions\Models\Wiki\BackfillStudios;
use App\Contracts\Actions\Models\Wiki\BackfillSynonyms;
use App\Enums\Actions\ActionStatus;
use App\Enums\Models\Wiki\AnimeSynonymType;
use App\Enums\Models\Wiki\SynonymType;
use App\Models\Wiki\Anime;
use Exception;
use Illuminate\Support\Arr;
@@ -27,8 +28,9 @@ use Illuminate\Support\Facades\Log;
class BackfillAnimeAction extends BackfillWikiAction
{
use CanCreateAnimeSynonym;
use CanCreateStudio;
use CanCreateSynonym;
use HasLabel;
final public const string STUDIOS = 'studios';
final public const string SYNONYMS = 'synonyms';
@@ -147,16 +149,16 @@ class BackfillAnimeAction extends BackfillWikiAction
$texts = [];
foreach ($api->getSynonyms() as $type => $text) {
if ($type === AnimeSynonymType::OTHER->value && in_array($text, $texts)) {
Log::info("Skipping duplicate synonym '$text' for Anime {$this->getModel()->getName()}");
if ($type === SynonymType::OTHER->value && in_array($text, $texts)) {
Log::info("Skipping duplicate synonym '$text' for {$this->privateLabel($this->getModel())} {$this->getModel()->getName()}");
continue;
}
$this->createAnimeSynonym($text, $type, $this->getModel());
$this->createSynonym($text, $type, $this->getModel());
$texts[] = $text;
}
if ($this->getModel()->animesynonyms()->exists()) {
if ($this->getModel()->synonyms()->exists()) {
$this->toBackfill[self::SYNONYMS] = false;
}
}
@@ -1,31 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Concerns\Models;
use App\Enums\Models\Wiki\AnimeSynonymType;
use App\Models\Wiki\Anime;
use App\Models\Wiki\Anime\AnimeSynonym;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
trait CanCreateAnimeSynonym
{
public function createAnimeSynonym(?string $text, int $type, Anime $anime): void
{
if (
blank($text)
|| ($type === AnimeSynonymType::OTHER->value && Str::is($text, $anime->getName(), true))
) {
return;
}
Log::info("Creating {$text} for Anime {$anime->getName()}");
$anime->animesynonyms()->create([
AnimeSynonym::ATTRIBUTE_TEXT => $text,
AnimeSynonym::ATTRIBUTE_TYPE => $type,
]);
}
}
+35
View File
@@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace App\Concerns\Models;
use App\Contracts\Models\HasSynonyms;
use App\Contracts\Models\Nameable;
use App\Enums\Models\Wiki\SynonymType;
use App\Models\Wiki\Synonym;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
trait CanCreateSynonym
{
use HasLabel;
public function createSynonym(?string $text, int $type, Model&Nameable&HasSynonyms $synonymable): void
{
if (
blank($text)
|| ($type === SynonymType::OTHER->value && Str::is($text, $synonymable->getName(), true))
) {
return;
}
Log::info("Creating {$text} for {$this->privateLabel($synonymable)} {$synonymable->getName()}");
$synonymable->synonyms()->create([
Synonym::ATTRIBUTE_TEXT => $text,
Synonym::ATTRIBUTE_TYPE => $type,
]);
}
}
@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace App\Contracts\Events;
use Illuminate\Contracts\Events\ShouldHandleEventsAfterCommit;
interface UpdateAnimeSynonymsEvent extends ShouldHandleEventsAfterCommit
{
public function updateAnimeSynonyms(): void;
}
@@ -1,7 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Contracts\GraphQL\Types;
interface SubmitableType {}
+21
View File
@@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace App\Contracts\Models;
use App\Models\Wiki\Synonym;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphMany;
interface HasSynonyms
{
public const SYNONYMS_RELATION = 'synonyms';
/**
* Get the synonyms for the owner model.
*
* @return MorphMany<Synonym, Model&HasSynonyms>
*/
public function synonyms(): MorphMany;
}
@@ -6,7 +6,12 @@ namespace App\Enums\Models\Wiki;
use App\Concerns\Enums\LocalizesName;
use Filament\Support\Contracts\HasLabel;
use GraphQL\Type\Definition\Deprecated as GraphQLDeprecated;
/**
* @deprecated Use SynonymType instead.
*/
#[GraphQLDeprecated('Use SynonymType instead.')]
enum AnimeSynonymType: int implements HasLabel
{
use LocalizesName;
+18
View File
@@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace App\Enums\Models\Wiki;
use App\Concerns\Enums\LocalizesName;
use Filament\Support\Contracts\HasLabel;
enum SynonymType: int implements HasLabel
{
use LocalizesName;
case OTHER = 0;
case NATIVE = 1;
case ENGLISH = 2;
case SHORT = 3;
}
+3 -3
View File
@@ -8,8 +8,8 @@ use App\Contracts\Events\CascadesDeletesEvent;
use App\Events\BaseEvent;
use App\Events\Wiki\Anime\Theme\ThemeDeleting;
use App\Models\Wiki\Anime;
use App\Models\Wiki\Anime\AnimeSynonym;
use App\Models\Wiki\Anime\AnimeTheme;
use App\Models\Wiki\Synonym;
use Illuminate\Support\Facades\Event;
/**
@@ -27,8 +27,8 @@ class AnimeDeleting extends BaseEvent implements CascadesDeletesEvent
$anime->discordthread?->delete();
$anime->animesynonyms->each(function (AnimeSynonym $synonym): void {
AnimeSynonym::withoutEvents(function () use ($synonym): void {
$anime->synonyms->each(function (Synonym $synonym): void {
Synonym::withoutEvents(function () use ($synonym): void {
$synonym->unsearchable();
$synonym->delete();
});
+3 -3
View File
@@ -7,9 +7,9 @@ namespace App\Events\Wiki\Anime;
use App\Contracts\Events\CascadesRestoresEvent;
use App\Events\Base\Wiki\WikiRestoredEvent;
use App\Models\Wiki\Anime;
use App\Models\Wiki\Anime\AnimeSynonym;
use App\Models\Wiki\Anime\AnimeTheme;
use App\Models\Wiki\Anime\Theme\AnimeThemeEntry;
use App\Models\Wiki\Synonym;
use App\Models\Wiki\Video;
use Illuminate\Database\Eloquent\SoftDeletingScope;
@@ -27,8 +27,8 @@ class AnimeRestored extends WikiRestoredEvent implements CascadesRestoresEvent
{
$anime = $this->getModel();
$anime->animesynonyms()->withoutGlobalScope(SoftDeletingScope::class)->get()->each(function (AnimeSynonym $synonym): void {
AnimeSynonym::withoutEvents(function () use ($synonym): void {
$anime->synonyms()->withoutGlobalScope(SoftDeletingScope::class)->get()->each(function (Synonym $synonym): void {
Synonym::withoutEvents(function () use ($synonym): void {
$synonym->restore();
$synonym->searchable();
});
@@ -1,42 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Events\Wiki\Anime\Synonym;
use App\Contracts\Events\UpdateRelatedIndicesEvent;
use App\Events\Base\Wiki\WikiCreatedEvent;
use App\Models\Wiki\Anime\AnimeSynonym;
use App\Models\Wiki\Anime\AnimeTheme;
use App\Models\Wiki\Anime\Theme\AnimeThemeEntry;
use App\Models\Wiki\Series;
use App\Models\Wiki\Video;
/**
* @extends WikiCreatedEvent<AnimeSynonym>
*/
class SynonymCreated extends WikiCreatedEvent implements UpdateRelatedIndicesEvent
{
protected function getDiscordMessageDescription(): string
{
return "Synonym '**{$this->getModel()->getName()}**' has been created for Anime '**{$this->getModel()->anime->getName()}**'.";
}
public function updateRelatedIndices(): void
{
$synonym = $this->getModel()->load([
AnimeSynonym::RELATION_SERIES,
AnimeSynonym::RELATION_VIDEOS,
]);
$synonym->anime->searchable();
$synonym->anime->series->each(fn (Series $series) => $series->searchable());
$synonym->anime->animethemes->each(function (AnimeTheme $theme): void {
$theme->searchable();
$theme->animethemeentries->each(function (AnimeThemeEntry $entry): void {
$entry->searchable();
$entry->videos->each(fn (Video $video) => $video->searchable());
});
});
}
}
@@ -1,54 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Events\Wiki\Anime\Synonym;
use App\Contracts\Events\UpdateRelatedIndicesEvent;
use App\Events\Base\Wiki\WikiDeletedEvent;
use App\Filament\Resources\Wiki\Anime\SynonymResource as SynonymFilament;
use App\Models\Wiki\Anime;
use App\Models\Wiki\Anime\AnimeSynonym;
use App\Models\Wiki\Anime\AnimeTheme;
use App\Models\Wiki\Anime\Theme\AnimeThemeEntry;
use App\Models\Wiki\Series;
use App\Models\Wiki\Video;
/**
* @extends WikiDeletedEvent<AnimeSynonym>
*/
class SynonymDeleted extends WikiDeletedEvent implements UpdateRelatedIndicesEvent
{
protected function getDiscordMessageDescription(): string
{
return "Synonym '**{$this->getModel()->getName()}**' has been deleted for Anime '**{$this->getModel()->anime->getName()}**'.";
}
protected function getNotificationMessage(): string
{
return "Synonym '{$this->getModel()->getName()}' has been deleted for Anime '{$this->getModel()->anime->getName()}'. It will be automatically pruned in one week. Please review.";
}
protected function getFilamentNotificationUrl(): string
{
return SynonymFilament::getUrl('view', ['record' => $this->getModel()]);
}
public function updateRelatedIndices(): void
{
$anime = $this->getModel()->anime->load([
Anime::RELATION_SERIES,
Anime::RELATION_VIDEOS,
]);
$anime->searchable();
$anime->series->each(fn (Series $series) => $series->searchable());
$anime->animethemes->each(function (AnimeTheme $theme): void {
$theme->searchable();
$theme->animethemeentries->each(function (AnimeThemeEntry $entry): void {
$entry->searchable();
$entry->videos->each(fn (Video $video) => $video->searchable());
});
});
}
}
@@ -1,42 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Events\Wiki\Anime\Synonym;
use App\Contracts\Events\UpdateRelatedIndicesEvent;
use App\Events\Base\Wiki\WikiRestoredEvent;
use App\Models\Wiki\Anime\AnimeSynonym;
use App\Models\Wiki\Anime\AnimeTheme;
use App\Models\Wiki\Anime\Theme\AnimeThemeEntry;
use App\Models\Wiki\Series;
use App\Models\Wiki\Video;
/**
* @extends WikiRestoredEvent<AnimeSynonym>
*/
class SynonymRestored extends WikiRestoredEvent implements UpdateRelatedIndicesEvent
{
protected function getDiscordMessageDescription(): string
{
return "Synonym '**{$this->getModel()->getName()}**' has been restored for Anime '**{$this->getModel()->anime->getName()}**'.";
}
public function updateRelatedIndices(): void
{
$synonym = $this->getModel()->load([
AnimeSynonym::RELATION_SERIES,
AnimeSynonym::RELATION_VIDEOS,
]);
$synonym->anime->searchable();
$synonym->anime->series->each(fn (Series $series) => $series->searchable());
$synonym->anime->animethemes->each(function (AnimeTheme $theme): void {
$theme->searchable();
$theme->animethemeentries->each(function (AnimeThemeEntry $entry): void {
$entry->searchable();
$entry->videos->each(fn (Video $video) => $video->searchable());
});
});
}
}
@@ -1,48 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Events\Wiki\Anime\Synonym;
use App\Contracts\Events\UpdateRelatedIndicesEvent;
use App\Events\Base\Wiki\WikiUpdatedEvent;
use App\Models\Wiki\Anime\AnimeSynonym;
use App\Models\Wiki\Anime\AnimeTheme;
use App\Models\Wiki\Anime\Theme\AnimeThemeEntry;
use App\Models\Wiki\Series;
use App\Models\Wiki\Video;
/**
* @extends WikiUpdatedEvent<AnimeSynonym>
*/
class SynonymUpdated extends WikiUpdatedEvent implements UpdateRelatedIndicesEvent
{
public function __construct(AnimeSynonym $synonym)
{
parent::__construct($synonym);
$this->initializeEmbedFields($synonym);
}
protected function getDiscordMessageDescription(): string
{
return "Synonym '**{$this->getModel()->getName()}**' has been updated for Anime '**{$this->getModel()->anime->getName()}**'.";
}
public function updateRelatedIndices(): void
{
$synonym = $this->getModel()->load([
AnimeSynonym::RELATION_SERIES,
AnimeSynonym::RELATION_VIDEOS,
]);
$synonym->anime->searchable();
$synonym->anime->series->each(fn (Series $series) => $series->searchable());
$synonym->anime->animethemes->each(function (AnimeTheme $theme): void {
$theme->searchable();
$theme->animethemeentries->each(function (AnimeThemeEntry $entry): void {
$entry->searchable();
$entry->videos->each(fn (Video $video) => $video->searchable());
});
});
}
}
@@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
namespace App\Events\Wiki\Synonym;
use App\Concerns\Models\HasLabel;
use App\Contracts\Events\UpdateAnimeSynonymsEvent;
use App\Contracts\Events\UpdateRelatedIndicesEvent;
use App\Events\Base\Wiki\WikiCreatedEvent;
use App\Models\Wiki\Anime;
use App\Models\Wiki\Anime\AnimeSynonym;
use App\Models\Wiki\Anime\AnimeTheme;
use App\Models\Wiki\Anime\Theme\AnimeThemeEntry;
use App\Models\Wiki\Series;
use App\Models\Wiki\Synonym;
use App\Models\Wiki\Video;
use Illuminate\Database\Eloquent\Relations\MorphTo;
/**
* @extends WikiCreatedEvent<Synonym>
*/
class SynonymCreated extends WikiCreatedEvent implements UpdateAnimeSynonymsEvent, UpdateRelatedIndicesEvent
{
use HasLabel;
protected function getDiscordMessageDescription(): string
{
return "Synonym '**{$this->getModel()->getName()}**' has been created for {$this->privateLabel($this->getModel()->synonymable)} '**{$this->getModel()->synonymable->getName()}**'.";
}
public function updateRelatedIndices(): void
{
$synonym = $this->getModel()->load([
Synonym::RELATION_SYNONYMABLE => fn (MorphTo $morphTo): MorphTo => $morphTo->morphWith([
Anime::class => [
Anime::RELATION_SERIES,
Anime::RELATION_VIDEOS,
],
]),
]);
if ($synonym->synonymable instanceof Anime) {
$synonym->synonymable->searchable();
$synonym->synonymable->series->each(fn (Series $series) => $series->searchable());
$synonym->synonymable->animethemes->each(function (AnimeTheme $theme): void {
$theme->searchable();
$theme->animethemeentries->each(function (AnimeThemeEntry $entry): void {
$entry->searchable();
$entry->videos->each(fn (Video $video) => $video->searchable());
});
});
}
}
public function updateAnimeSynonyms(): void
{
if ($this->getModel()->synonymable instanceof Anime) {
AnimeSynonym::query()->create([
AnimeSynonym::ATTRIBUTE_ANIME => $this->getModel()->synonymable_id,
AnimeSynonym::ATTRIBUTE_TEXT => $this->getModel()->text,
AnimeSynonym::ATTRIBUTE_TYPE => $this->getModel()->type->value,
]);
}
}
}
@@ -0,0 +1,76 @@
<?php
declare(strict_types=1);
namespace App\Events\Wiki\Synonym;
use App\Concerns\Models\HasLabel;
use App\Contracts\Events\UpdateAnimeSynonymsEvent;
use App\Contracts\Events\UpdateRelatedIndicesEvent;
use App\Events\Base\Wiki\WikiDeletedEvent;
use App\Filament\Resources\Wiki\SynonymResource as SynonymFilament;
use App\Models\Wiki\Anime;
use App\Models\Wiki\Anime\AnimeSynonym;
use App\Models\Wiki\Anime\AnimeTheme;
use App\Models\Wiki\Anime\Theme\AnimeThemeEntry;
use App\Models\Wiki\Series;
use App\Models\Wiki\Synonym;
use App\Models\Wiki\Video;
use Illuminate\Database\Eloquent\Relations\MorphTo;
/**
* @extends WikiDeletedEvent<Synonym>
*/
class SynonymDeleted extends WikiDeletedEvent implements UpdateAnimeSynonymsEvent, UpdateRelatedIndicesEvent
{
use HasLabel;
protected function getDiscordMessageDescription(): string
{
return "Synonym '**{$this->getModel()->getName()}**' has been deleted for {$this->privateLabel($this->getModel()->synonymable)} '**{$this->getModel()->synonymable->getName()}**'.";
}
protected function getNotificationMessage(): string
{
return "Synonym '{$this->getModel()->getName()}' has been deleted for {$this->privateLabel($this->getModel()->synonymable)} '{$this->getModel()->synonymable->getName()}'. It will be automatically pruned in one week. Please review.";
}
protected function getFilamentNotificationUrl(): string
{
return SynonymFilament::getUrl('view', ['record' => $this->getModel()]);
}
public function updateRelatedIndices(): void
{
$synonym = $this->getModel()->load([
Synonym::RELATION_SYNONYMABLE => fn (MorphTo $morphTo): MorphTo => $morphTo->morphWith([
Anime::class => [
Anime::RELATION_SERIES,
Anime::RELATION_VIDEOS,
],
]),
]);
if ($synonym->synonymable instanceof Anime) {
$synonym->synonymable->searchable();
$synonym->synonymable->series->each(fn (Series $series) => $series->searchable());
$synonym->synonymable->animethemes->each(function (AnimeTheme $theme): void {
$theme->searchable();
$theme->animethemeentries->each(function (AnimeThemeEntry $entry): void {
$entry->searchable();
$entry->videos->each(fn (Video $video) => $video->searchable());
});
});
}
}
public function updateAnimeSynonyms(): void
{
if ($this->getModel()->synonymable instanceof Anime) {
AnimeSynonym::query()
->where(AnimeSynonym::ATTRIBUTE_ANIME, $this->getModel()->synonymable_id)
->where(AnimeSynonym::ATTRIBUTE_TEXT, $this->getModel()->text)
->{$this->getModel()->isForceDeleting() ? 'forceDelete' : 'delete'}();
}
}
}
@@ -0,0 +1,67 @@
<?php
declare(strict_types=1);
namespace App\Events\Wiki\Synonym;
use App\Concerns\Models\HasLabel;
use App\Contracts\Events\UpdateAnimeSynonymsEvent;
use App\Contracts\Events\UpdateRelatedIndicesEvent;
use App\Events\Base\Wiki\WikiRestoredEvent;
use App\Models\Wiki\Anime;
use App\Models\Wiki\Anime\AnimeSynonym;
use App\Models\Wiki\Anime\AnimeTheme;
use App\Models\Wiki\Anime\Theme\AnimeThemeEntry;
use App\Models\Wiki\Series;
use App\Models\Wiki\Synonym;
use App\Models\Wiki\Video;
use Illuminate\Database\Eloquent\Relations\MorphTo;
/**
* @extends WikiRestoredEvent<Synonym>
*/
class SynonymRestored extends WikiRestoredEvent implements UpdateAnimeSynonymsEvent, UpdateRelatedIndicesEvent
{
use HasLabel;
protected function getDiscordMessageDescription(): string
{
return "Synonym '**{$this->getModel()->getName()}**' has been restored for {$this->privateLabel($this->getModel()->synonymable)} '**{$this->getModel()->synonymable->getName()}**'.";
}
public function updateRelatedIndices(): void
{
$synonym = $this->getModel()->load([
Synonym::RELATION_SYNONYMABLE => fn (MorphTo $morphTo): MorphTo => $morphTo->morphWith([
Anime::class => [
Anime::RELATION_SERIES,
Anime::RELATION_VIDEOS,
],
]),
]);
if ($synonym->synonymable instanceof Anime) {
$synonym->synonymable->searchable();
$synonym->synonymable->series->each(fn (Series $series) => $series->searchable());
$synonym->synonymable->animethemes->each(function (AnimeTheme $theme): void {
$theme->searchable();
$theme->animethemeentries->each(function (AnimeThemeEntry $entry): void {
$entry->searchable();
$entry->videos->each(fn (Video $video) => $video->searchable());
});
});
}
}
public function updateAnimeSynonyms(): void
{
if ($this->getModel()->synonymable instanceof Anime) {
AnimeSynonym::query()
->withTrashed()
->where(AnimeSynonym::ATTRIBUTE_ANIME, $this->getModel()->synonymable_id)
->where(AnimeSynonym::ATTRIBUTE_TEXT, $this->getModel()->text)
->first()
?->restore();
}
}
}
@@ -0,0 +1,74 @@
<?php
declare(strict_types=1);
namespace App\Events\Wiki\Synonym;
use App\Concerns\Models\HasLabel;
use App\Contracts\Events\UpdateAnimeSynonymsEvent;
use App\Contracts\Events\UpdateRelatedIndicesEvent;
use App\Events\Base\Wiki\WikiUpdatedEvent;
use App\Models\Wiki\Anime;
use App\Models\Wiki\Anime\AnimeSynonym;
use App\Models\Wiki\Anime\AnimeTheme;
use App\Models\Wiki\Anime\Theme\AnimeThemeEntry;
use App\Models\Wiki\Series;
use App\Models\Wiki\Synonym;
use App\Models\Wiki\Video;
use Illuminate\Database\Eloquent\Relations\MorphTo;
/**
* @extends WikiUpdatedEvent<Synonym>
*/
class SynonymUpdated extends WikiUpdatedEvent implements UpdateAnimeSynonymsEvent, UpdateRelatedIndicesEvent
{
use HasLabel;
public function __construct(Synonym $synonym)
{
parent::__construct($synonym);
$this->initializeEmbedFields($synonym);
}
protected function getDiscordMessageDescription(): string
{
return "Synonym '**{$this->getModel()->getName()}**' has been updated for {$this->privateLabel($this->getModel()->synonymable)} '**{$this->getModel()->synonymable->getName()}**'.";
}
public function updateRelatedIndices(): void
{
$synonym = $this->getModel()->load([
Synonym::RELATION_SYNONYMABLE => fn (MorphTo $morphTo): MorphTo => $morphTo->morphWith([
Anime::class => [
Anime::RELATION_SERIES,
Anime::RELATION_VIDEOS,
],
]),
]);
if ($synonym->synonymable instanceof Anime) {
$synonym->synonymable->searchable();
$synonym->synonymable->series->each(fn (Series $series) => $series->searchable());
$synonym->synonymable->animethemes->each(function (AnimeTheme $theme): void {
$theme->searchable();
$theme->animethemeentries->each(function (AnimeThemeEntry $entry): void {
$entry->searchable();
$entry->videos->each(fn (Video $video) => $video->searchable());
});
});
}
}
public function updateAnimeSynonyms(): void
{
if ($this->getModel()->synonymable instanceof Anime) {
AnimeSynonym::query()
->where(AnimeSynonym::ATTRIBUTE_ANIME, $this->getModel()->getOriginal(Synonym::ATTRIBUTE_SYNONYMABLE_ID))
->where(AnimeSynonym::ATTRIBUTE_TEXT, $this->getModel()->getOriginal(Synonym::ATTRIBUTE_TEXT))
->update([
AnimeSynonym::ATTRIBUTE_TEXT => $this->getModel()->text,
AnimeSynonym::ATTRIBUTE_TYPE => $this->getModel()->type->value,
]);
}
}
}
@@ -97,7 +97,7 @@ class BackfillAnimeAction extends BaseAction
return $schema;
}
$anime = $anime->load([Anime::RELATION_RESOURCES, Anime::RELATION_IMAGES, Anime::RELATION_STUDIOS, Anime::RELATION_SYNONYMS]);
$anime = $anime->load([Anime::RELATION_RESOURCES, Anime::RELATION_IMAGES, Anime::RELATION_STUDIOS, Anime::RELATION_ANIMESYNONYMS]);
$resources = $anime->resources->pluck(ExternalResource::ATTRIBUTE_SITE)->keyBy(fn (ResourceSite $site) => $site->value)->keys();
$images = $anime->images->pluck(Image::ATTRIBUTE_FACET)->keyBy(fn (ImageFacet $facet) => $facet->value)->keys();
@@ -173,7 +173,7 @@ class BackfillAnimeAction extends BaseAction
Checkbox::make(self::BACKFILL_SYNONYMS)
->label(__('filament.actions.anime.backfill.fields.synonyms.name'))
->helperText(__('filament.actions.anime.backfill.fields.synonyms.help'))
->default(fn () => $anime->animesynonyms->isEmpty()),
->default(fn () => $anime->synonyms->isEmpty()),
]),
]);
}
@@ -2,12 +2,12 @@
declare(strict_types=1);
namespace App\Filament\RelationManagers\Wiki\Anime;
namespace App\Filament\RelationManagers\Wiki;
use App\Filament\RelationManagers\BaseRelationManager;
use App\Filament\Resources\BaseResource;
use App\Filament\Resources\Wiki\Anime\SynonymResource;
use App\Models\Wiki\Anime\AnimeSynonym;
use App\Filament\Resources\Wiki\SynonymResource;
use App\Models\Wiki\Synonym;
use Filament\Tables\Table;
abstract class SynonymRelationManager extends BaseRelationManager
@@ -23,8 +23,8 @@ abstract class SynonymRelationManager extends BaseRelationManager
{
return parent::table(
$table
->recordTitleAttribute(AnimeSynonym::ATTRIBUTE_TEXT)
->defaultSort(AnimeSynonym::TABLE.'.'.AnimeSynonym::ATTRIBUTE_ID, 'desc')
->recordTitleAttribute(Synonym::ATTRIBUTE_TEXT)
->defaultSort(Synonym::TABLE.'.'.Synonym::ATTRIBUTE_ID, 'desc')
);
}
}
@@ -140,7 +140,7 @@ class PlaylistResource extends BaseResource
TextColumn::make(Playlist::ATTRIBUTE_NAME)
->label(__('filament.fields.playlist.name.name'))
->limit(40)
->tooltip(fn (TextColumn $column): mixed => $column->getState())
->tooltip(fn (string $state): string => $state)
->copyableWithMessage(),
TextColumn::make(Playlist::ATTRIBUTE_VISIBILITY)
@@ -4,9 +4,9 @@ declare(strict_types=1);
namespace App\Filament\Resources\Wiki\Anime\RelationManagers;
use App\Filament\RelationManagers\Wiki\Anime\SynonymRelationManager;
use App\Filament\RelationManagers\Wiki\SynonymRelationManager;
use App\Models\Wiki\Anime;
use App\Models\Wiki\Anime\AnimeSynonym;
use App\Models\Wiki\Synonym;
use Filament\Tables\Table;
class SynonymAnimeRelationManager extends SynonymRelationManager
@@ -20,7 +20,7 @@ class SynonymAnimeRelationManager extends SynonymRelationManager
{
return parent::table(
$table
->inverseRelationship(AnimeSynonym::RELATION_ANIME)
->inverseRelationship(Synonym::RELATION_SYNONYMABLE)
);
}
}
@@ -206,7 +206,7 @@ class EntryResource extends BaseResource
TextColumn::make(AnimeThemeEntry::ATTRIBUTE_NOTES)
->label(__('filament.fields.anime_theme_entry.notes.name'))
->limit(50)
->tooltip(fn (TextColumn $column): mixed => $column->getState()),
->tooltip(fn (string $state): string => $state),
BelongsToColumn::make(AnimeThemeEntry::RELATION_SONG_SHALLOW, SongResource::class)
->hiddenOn(EntryThemeRelationManager::class)
@@ -146,12 +146,12 @@ class AnimeResource extends BaseResource
->label(__('filament.fields.anime.name.name'))
->copyableWithMessage()
->limit(50)
->tooltip(fn (TextColumn $column): mixed => $column->getState()),
->tooltip(fn (string $state): string => $state),
TextColumn::make(Anime::ATTRIBUTE_SLUG)
->label(__('filament.fields.anime.slug.name'))
->limit(20)
->tooltip(fn (TextColumn $column): mixed => $column->getState()),
->tooltip(fn (string $state): string => $state),
TextColumn::make(Anime::ATTRIBUTE_YEAR)
->label(__('filament.fields.anime.year.name')),
@@ -2,11 +2,11 @@
declare(strict_types=1);
namespace App\Filament\Resources\Wiki\Anime\Synonym\Pages;
namespace App\Filament\Resources\Wiki\Synonym\Pages;
use App\Filament\Resources\Base\BaseListResources;
use App\Filament\Resources\Wiki\Anime\SynonymResource;
use App\Models\Wiki\Anime\AnimeSynonym;
use App\Filament\Resources\Wiki\SynonymResource;
use App\Models\Wiki\Synonym;
use Illuminate\Database\Eloquent\Builder;
class ListSynonyms extends BaseListResources
@@ -18,6 +18,6 @@ class ListSynonyms extends BaseListResources
*/
protected function applySearchToTableQuery(Builder $query): Builder
{
return $this->makeScout($query, AnimeSynonym::class);
return $this->makeScout($query, Synonym::class);
}
}
@@ -2,10 +2,10 @@
declare(strict_types=1);
namespace App\Filament\Resources\Wiki\Anime\Synonym\Pages;
namespace App\Filament\Resources\Wiki\Synonym\Pages;
use App\Filament\Resources\Base\BaseViewResource;
use App\Filament\Resources\Wiki\Anime\SynonymResource;
use App\Filament\Resources\Wiki\SynonymResource;
class ViewSynonym extends BaseViewResource
{
@@ -2,31 +2,27 @@
declare(strict_types=1);
namespace App\Filament\Resources\Wiki\Anime;
namespace App\Filament\Resources\Wiki;
use App\Enums\Filament\NavigationGroup;
use App\Enums\Models\Wiki\AnimeSynonymType;
use App\Filament\Components\Columns\BelongsToColumn;
use App\Enums\Models\Wiki\SynonymType;
use App\Filament\Components\Columns\TextColumn;
use App\Filament\Components\Fields\BelongsTo;
use App\Filament\Components\Fields\Select;
use App\Filament\Components\Fields\TextInput;
use App\Filament\Components\Infolist\BelongsToEntry;
use App\Filament\Components\Infolist\TextEntry;
use App\Filament\Components\Infolist\TimestampSection;
use App\Filament\RelationManagers\Wiki\Anime\SynonymRelationManager;
use App\Filament\Resources\BaseResource;
use App\Filament\Resources\Wiki\Anime\RelationManagers\SynonymAnimeRelationManager;
use App\Filament\Resources\Wiki\Anime\Synonym\Pages\ListSynonyms;
use App\Filament\Resources\Wiki\Anime\Synonym\Pages\ViewSynonym;
use App\Filament\Resources\Wiki\AnimeResource;
use App\Filament\Submission\Resources\Anime\Pages\CreateAnimeSubmission;
use App\Models\Wiki\Anime\AnimeSynonym;
use App\Filament\Resources\Wiki\Synonym\Pages\ListSynonyms;
use App\Filament\Resources\Wiki\Synonym\Pages\ViewSynonym;
use App\Models\Wiki\Synonym;
use Filament\Facades\Filament;
use Filament\QueryBuilder\Constraints\SelectConstraint;
use Filament\QueryBuilder\Constraints\TextConstraint;
use Filament\Resources\RelationManagers\RelationGroup;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Schema;
use Filament\Support\Enums\FontWeight;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Filters\QueryBuilder;
use Filament\Tables\Table;
@@ -40,16 +36,16 @@ class SynonymResource extends BaseResource
*
* @var class-string<Model>|null
*/
protected static ?string $model = AnimeSynonym::class;
protected static ?string $model = Synonym::class;
public static function getModelLabel(): string
{
return __('filament.resources.singularLabel.anime_synonym');
return __('filament.resources.singularLabel.synonym');
}
public static function getPluralModelLabel(): string
{
return __('filament.resources.label.anime_synonyms');
return __('filament.resources.label.synonyms');
}
public static function getNavigationGroup(): NavigationGroup
@@ -64,12 +60,12 @@ class SynonymResource extends BaseResource
public static function getRecordSlug(): string
{
return 'anime-synonyms';
return 'synonyms';
}
public static function getRecordTitleAttribute(): string
{
return AnimeSynonym::ATTRIBUTE_TEXT;
return Synonym::ATTRIBUTE_TEXT;
}
public static function getEloquentQuery(): Builder
@@ -77,26 +73,22 @@ class SynonymResource extends BaseResource
$query = parent::getEloquentQuery();
// Necessary to prevent lazy loading when loading related resources
return $query->with([AnimeSynonym::RELATION_ANIME]);
return $query->with([Synonym::RELATION_SYNONYMABLE]);
}
public static function form(Schema $schema): Schema
{
return $schema
->components([
BelongsTo::make(AnimeSynonym::ATTRIBUTE_ANIME)
->resource(AnimeResource::class)
->hiddenOn([SynonymRelationManager::class, CreateAnimeSubmission::class]),
Select::make(AnimeSynonym::ATTRIBUTE_TYPE)
->label(__('filament.fields.anime_synonym.type.name'))
->helperText(__('filament.fields.anime_synonym.type.help'))
->options(AnimeSynonymType::class)
Select::make(Synonym::ATTRIBUTE_TYPE)
->label(__('filament.fields.synonym.type.name'))
->helperText(__('filament.fields.synonym.type.help'))
->options(SynonymType::class)
->required(),
TextInput::make(AnimeSynonym::ATTRIBUTE_TEXT)
->label(__('filament.fields.anime_synonym.text.name'))
->helperText(__('filament.fields.anime_synonym.text.help'))
TextInput::make(Synonym::ATTRIBUTE_TEXT)
->label(__('filament.fields.synonym.text.name'))
->helperText(__('filament.fields.synonym.text.help'))
->required()
->maxLength(255),
])
@@ -107,20 +99,28 @@ class SynonymResource extends BaseResource
{
return parent::table($table)
->columns([
TextColumn::make(AnimeSynonym::ATTRIBUTE_ID)
TextColumn::make(Synonym::ATTRIBUTE_ID)
->label(__('filament.fields.base.id')),
BelongsToColumn::make(AnimeSynonym::RELATION_ANIME, AnimeResource::class)
->hiddenOn(SynonymAnimeRelationManager::class),
TextColumn::make(Synonym::RELATION_SYNONYMABLE)
->hiddenOn(SynonymAnimeRelationManager::class)
->color('related-link')
->weight(FontWeight::SemiBold)
->state(fn (Synonym $record) => $record->synonymable->getName())
->url(function (Synonym $record): string {
$synonymable = $record->synonymable;
TextColumn::make(AnimeSynonym::ATTRIBUTE_TYPE)
->label(__('filament.fields.anime_synonym.type.name'))
->formatStateUsing(fn (AnimeSynonymType $state): ?string => $state->localize()),
return Filament::getModelResource($synonymable)::getUrl('view', ['record' => $synonymable]);
}),
TextColumn::make(AnimeSynonym::ATTRIBUTE_TEXT)
->label(__('filament.fields.anime_synonym.text.name'))
TextColumn::make(Synonym::ATTRIBUTE_TYPE)
->label(__('filament.fields.synonym.type.name'))
->formatStateUsing(fn (SynonymType $state): ?string => $state->localize()),
TextColumn::make(Synonym::ATTRIBUTE_TEXT)
->label(__('filament.fields.synonym.text.name'))
->limit(50)
->tooltip(fn (TextColumn $column): mixed => $column->getState()),
->tooltip(fn (string $state): string => $state),
])
->searchable();
}
@@ -131,17 +131,25 @@ class SynonymResource extends BaseResource
->components([
Section::make(static::getRecordTitle($schema->getRecord()))
->schema([
TextEntry::make(AnimeSynonym::ATTRIBUTE_ID)
TextEntry::make(Synonym::ATTRIBUTE_ID)
->label(__('filament.fields.base.id')),
BelongsToEntry::make(AnimeSynonym::RELATION_ANIME, AnimeResource::class),
TextEntry::make(Synonym::RELATION_SYNONYMABLE)
->color('related-link')
->weight(FontWeight::SemiBold)
->state(fn (Synonym $record) => $record->synonymable->getName())
->url(function (Synonym $record): string {
$synonymable = $record->synonymable;
TextEntry::make(AnimeSynonym::ATTRIBUTE_TYPE)
->label(__('filament.fields.anime_synonym.type.name'))
->formatStateUsing(fn (AnimeSynonymType $state): ?string => $state->localize()),
return Filament::getModelResource($synonymable)::getUrl('view', ['record' => $synonymable]);
}),
TextEntry::make(AnimeSynonym::ATTRIBUTE_TEXT)
->label(__('filament.fields.anime_synonym.text.name'))
TextEntry::make(Synonym::ATTRIBUTE_TYPE)
->label(__('filament.fields.synonym.type.name'))
->formatStateUsing(fn (SynonymType $state): ?string => $state->localize()),
TextEntry::make(Synonym::ATTRIBUTE_TEXT)
->label(__('filament.fields.synonym.text.name'))
->columnSpanFull(),
])
->columns(3),
@@ -159,12 +167,12 @@ class SynonymResource extends BaseResource
return [
QueryBuilder::make()
->constraints([
TextConstraint::make(AnimeSynonym::ATTRIBUTE_TEXT)
->label(__('filament.fields.anime_synonym.text.name')),
TextConstraint::make(Synonym::ATTRIBUTE_TEXT)
->label(__('filament.fields.synonym.text.name')),
SelectConstraint::make(AnimeSynonym::ATTRIBUTE_TYPE)
->label(__('filament.fields.anime_synonym.type.name'))
->options(AnimeSynonymType::class)
SelectConstraint::make(Synonym::ATTRIBUTE_TYPE)
->label(__('filament.fields.synonym.type.name'))
->options(SynonymType::class)
->multiple(),
...parent::getConstraints(),
@@ -186,6 +194,11 @@ class SynonymResource extends BaseResource
];
}
public static function canCreate(): bool
{
return false;
}
/**
* @return array<string, \Filament\Resources\Pages\PageRegistration>
*/
@@ -9,7 +9,6 @@ use App\Filament\Actions\Models\Wiki\Song\LoadArtistsAction;
use App\Filament\Actions\Models\Wiki\Song\Performance\LoadMembersAction;
use App\Filament\Components\Fields\SubmissionBelongsTo;
use App\Filament\Components\Fields\TextInput;
use App\Filament\Resources\Wiki\Anime\SynonymResource;
use App\Filament\Resources\Wiki\Anime\Theme\EntryResource;
use App\Filament\Resources\Wiki\Anime\Theme\Schemas\ThemeForm;
use App\Filament\Resources\Wiki\AnimeResource;
@@ -20,6 +19,7 @@ use App\Filament\Resources\Wiki\SeriesResource;
use App\Filament\Resources\Wiki\Song\RelationManagers\PerformanceSongRelationManager;
use App\Filament\Resources\Wiki\SongResource;
use App\Filament\Resources\Wiki\StudioResource;
use App\Filament\Resources\Wiki\SynonymResource;
use App\Filament\Submission\Resources\AnimeSubmissionResource;
use App\Models\User\Submission;
use App\Models\User\Submission\SubmissionStage;
@@ -69,11 +69,11 @@ class CreateAnimeSubmission extends CreateRecord
->schema(AnimeResource::form($schema)->getComponents()),
Tab::make(Anime::RELATION_SYNONYMS)
->label(__('filament.resources.label.anime_synonyms'))
->label(__('filament.resources.label.synonyms'))
->schema([
Repeater::make(Anime::RELATION_SYNONYMS)
->label(__('filament.resources.label.anime_synonyms'))
->addActionLabel(__('filament.buttons.add', ['label' => __('filament.resources.singularLabel.anime_synonym')]))
->label(__('filament.resources.label.synonyms'))
->addActionLabel(__('filament.buttons.add', ['label' => __('filament.resources.singularLabel.synonym')]))
->defaultItems(0)
->schema(SynonymResource::form($schema)->getComponents()),
]),
+9
View File
@@ -18,6 +18,8 @@ abstract class Field
{
use ResolvesArguments;
public ?string $deprecationReason = null;
public function __construct(
protected string $column,
protected ?string $name = null,
@@ -66,6 +68,13 @@ abstract class Field
return $type;
}
public function deprecate(string $reason): self
{
$this->deprecationReason = $reason;
return $this;
}
/**
* @return Type|BaseType
*/
@@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
namespace App\GraphQL\Schema\Fields\Wiki\Synonym;
use App\Contracts\GraphQL\Fields\CreatableField;
use App\Contracts\GraphQL\Fields\RequiredOnCreation;
use App\Contracts\GraphQL\Fields\UpdatableField;
use App\GraphQL\Schema\Fields\StringField;
use App\Models\Wiki\Synonym;
class SynonymTextField extends StringField implements CreatableField, RequiredOnCreation, UpdatableField
{
public function __construct()
{
parent::__construct(Synonym::ATTRIBUTE_TEXT, nullable: false);
}
public function description(): string
{
return 'The alternate title or common abbreviations';
}
/**
* @param array<string, mixed> $args
*/
public function getCreationRules(array $args): array
{
return [
'required',
'string',
'max:192',
];
}
/**
* @param array<string, mixed> $args
*/
public function getUpdateRules(array $args): array
{
return [
'sometimes',
'required',
'string',
'max:192',
];
}
}
@@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
namespace App\GraphQL\Schema\Fields\Wiki\Synonym;
use App\Contracts\GraphQL\Fields\CreatableField;
use App\Contracts\GraphQL\Fields\RequiredOnCreation;
use App\Contracts\GraphQL\Fields\UpdatableField;
use App\Enums\Models\Wiki\SynonymType;
use App\GraphQL\Schema\Fields\EnumField;
use App\Models\Wiki\Synonym;
use Illuminate\Validation\Rules\Enum;
class SynonymTypeField extends EnumField implements CreatableField, RequiredOnCreation, UpdatableField
{
public function __construct()
{
parent::__construct(Synonym::ATTRIBUTE_TYPE, SynonymType::class, nullable: false);
}
public function description(): string
{
return 'The type of the synonym';
}
/**
* @param array<string, mixed> $args
*/
public function getCreationRules(array $args): array
{
return [
'required',
new Enum(SynonymType::class),
];
}
/**
* @param array<string, mixed> $args
*/
public function getUpdateRules(array $args): array
{
return [
'sometimes',
'required',
new Enum(SynonymType::class),
];
}
}
+2
View File
@@ -7,6 +7,7 @@ namespace App\GraphQL\Schema\Queries;
use App\Concerns\Actions\GraphQL\ConstrainsEagerLoads;
use App\Concerns\Actions\GraphQL\FiltersModels;
use App\Concerns\GraphQL\ResolvesArguments;
use App\Contracts\GraphQL\Fields\DeprecatedField;
use App\GraphQL\Argument\Argument;
use App\GraphQL\Argument\FirstArgument;
use App\GraphQL\Argument\PageArgument;
@@ -49,6 +50,7 @@ abstract class BaseQuery extends Query
'name' => $this->getName(),
'description' => $this->description(),
'baseType' => $this->baseType(),
'deprecationReason' => $this instanceof DeprecatedField ? $this->deprecationReason() : null,
];
}
@@ -4,10 +4,11 @@ declare(strict_types=1);
namespace App\GraphQL\Schema\Queries\Models\Pagination\Wiki\Anime;
use App\Contracts\GraphQL\Fields\DeprecatedField;
use App\GraphQL\Schema\Queries\Models\Pagination\EloquentPaginationQuery;
use App\GraphQL\Schema\Types\Wiki\Anime\AnimeSynonymType;
class AnimeSynonymPaginationQuery extends EloquentPaginationQuery
class AnimeSynonymPaginationQuery extends EloquentPaginationQuery implements DeprecatedField
{
public function __construct()
{
@@ -26,4 +27,9 @@ class AnimeSynonymPaginationQuery extends EloquentPaginationQuery
{
return new AnimeSynonymType();
}
public function deprecationReason(): string
{
return 'Use synonymPagination query instead.';
}
}
@@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
namespace App\GraphQL\Schema\Queries\Models\Pagination\Wiki;
use App\GraphQL\Schema\Queries\Models\Pagination\EloquentPaginationQuery;
use App\GraphQL\Schema\Types\Wiki\SynonymType;
class SynonymPaginationQuery extends EloquentPaginationQuery
{
public function __construct()
{
parent::__construct('synonymPagination');
}
public function description(): string
{
return 'Returns a listing of synonyms resources given fields.';
}
/**
* The base return type of the query.
*/
public function baseType(): SynonymType
{
return new SynonymType();
}
}
+6
View File
@@ -36,6 +36,7 @@ use App\GraphQL\Schema\Queries\Models\Pagination\Wiki\Song\MembershipPaginationQ
use App\GraphQL\Schema\Queries\Models\Pagination\Wiki\Song\PerformancePaginationQuery;
use App\GraphQL\Schema\Queries\Models\Pagination\Wiki\SongPaginationQuery;
use App\GraphQL\Schema\Queries\Models\Pagination\Wiki\StudioPaginationQuery;
use App\GraphQL\Schema\Queries\Models\Pagination\Wiki\SynonymPaginationQuery;
use App\GraphQL\Schema\Queries\Models\Pagination\Wiki\ThemeGroupPaginationQuery;
use App\GraphQL\Schema\Queries\Models\Pagination\Wiki\Video\VideoScriptPaginationQuery;
use App\GraphQL\Schema\Queries\Models\Pagination\Wiki\VideoPaginationQuery;
@@ -91,6 +92,7 @@ use App\GraphQL\Schema\Types\Wiki\Song\MembershipType;
use App\GraphQL\Schema\Types\Wiki\Song\PerformanceType;
use App\GraphQL\Schema\Types\Wiki\SongType;
use App\GraphQL\Schema\Types\Wiki\StudioType;
use App\GraphQL\Schema\Types\Wiki\SynonymType;
use App\GraphQL\Schema\Types\Wiki\ThemeGroupType;
use App\GraphQL\Schema\Types\Wiki\Video\VideoScriptType;
use App\GraphQL\Schema\Types\Wiki\VideoType;
@@ -99,6 +101,7 @@ use App\GraphQL\Schema\Unions\LikeableUnion;
use App\GraphQL\Schema\Unions\NotificationUnion;
use App\GraphQL\Schema\Unions\PerformanceArtistUnion;
use App\GraphQL\Schema\Unions\ResourceableUnion;
use App\GraphQL\Schema\Unions\SynonymableUnion;
use App\Http\Middleware\GraphQL\LogGraphQLRequest;
use App\Http\Middleware\GraphQL\MaxCount;
use Illuminate\Support\Facades\Config;
@@ -153,6 +156,7 @@ class V1Schema implements ConfigConvertible
SongPaginationQuery::class,
StudioQuery::class,
StudioPaginationQuery::class,
SynonymPaginationQuery::class,
ThemeGroupPaginationQuery::class,
VideoQuery::class,
VideoPaginationQuery::class,
@@ -219,6 +223,7 @@ class V1Schema implements ConfigConvertible
SeriesType::class,
SongType::class,
StudioType::class,
SynonymType::class,
ThemeGroupType::class,
VideoType::class,
VideoScriptType::class,
@@ -246,6 +251,7 @@ class V1Schema implements ConfigConvertible
NotificationUnion::class,
PerformanceArtistUnion::class,
ResourceableUnion::class,
SynonymableUnion::class,
// Scalars
MixedScalar::class,
+2 -3
View File
@@ -78,6 +78,7 @@ abstract class BaseType extends RebingType
'type' => $relation->type(),
'args' => $relation->args(),
'resolve' => $relation->resolve(...),
'deprecationReason' => $relation instanceof DeprecatedField ? $relation->deprecationReason() : $relation->deprecationReason,
],
]);
@@ -91,10 +92,8 @@ abstract class BaseType extends RebingType
'alias' => $field->getColumn(),
'args' => $field->args(),
'resolve' => $field->resolve(...),
'deprecationReason' => $field instanceof DeprecatedField ? $field->deprecationReason() : $field->deprecationReason,
'fieldClass' => $field,
...($field instanceof DeprecatedField ? ['deprecationReason' => $field->deprecationReason()] : []),
],
]);
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\GraphQL\Schema\Types\Document;
use App\Contracts\GraphQL\Types\SubmitableType;
use App\GraphQL\Schema\Fields\Base\CreatedAtField;
use App\GraphQL\Schema\Fields\Base\DeletedAtField;
use App\GraphQL\Schema\Fields\Base\IdUnbindableField;
@@ -17,7 +16,7 @@ use App\GraphQL\Schema\Fields\Relations\BelongsToRelation;
use App\GraphQL\Schema\Types\EloquentType;
use App\Models\Document\Page;
class PageType extends EloquentType implements SubmitableType
class PageType extends EloquentType
{
public function description(): string
{
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\GraphQL\Schema\Types\Pivot\Morph;
use App\Contracts\GraphQL\Types\SubmitableType;
use App\GraphQL\Schema\Fields\Base\CreatedAtField;
use App\GraphQL\Schema\Fields\Base\UpdatedAtField;
use App\GraphQL\Schema\Fields\Field;
@@ -16,7 +15,7 @@ use App\GraphQL\Schema\Types\Wiki\ImageType;
use App\GraphQL\Schema\Unions\ImageableUnion;
use App\Pivots\Morph\Imageable;
class ImageableType extends PivotType implements SubmitableType
class ImageableType extends PivotType
{
public function description(): string
{
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\GraphQL\Schema\Types\Pivot\Morph;
use App\Contracts\GraphQL\Types\SubmitableType;
use App\GraphQL\Schema\Fields\Base\CreatedAtField;
use App\GraphQL\Schema\Fields\Base\UpdatedAtField;
use App\GraphQL\Schema\Fields\Field;
@@ -16,7 +15,7 @@ use App\GraphQL\Schema\Types\Wiki\ExternalResourceType;
use App\GraphQL\Schema\Unions\ResourceableUnion;
use App\Pivots\Morph\Resourceable;
class ResourceableType extends PivotType implements SubmitableType
class ResourceableType extends PivotType
{
public function description(): string
{
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\GraphQL\Schema\Types\Pivot\Wiki;
use App\Contracts\GraphQL\Types\SubmitableType;
use App\GraphQL\Schema\Fields\Base\CreatedAtField;
use App\GraphQL\Schema\Fields\Base\UpdatedAtField;
use App\GraphQL\Schema\Fields\Field;
@@ -14,7 +13,7 @@ use App\GraphQL\Schema\Types\Wiki\AnimeType;
use App\GraphQL\Schema\Types\Wiki\SeriesType;
use App\Pivots\Wiki\AnimeSeries;
class AnimeSeriesType extends PivotType implements SubmitableType
class AnimeSeriesType extends PivotType
{
public function description(): string
{
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\GraphQL\Schema\Types\Pivot\Wiki;
use App\Contracts\GraphQL\Types\SubmitableType;
use App\GraphQL\Schema\Fields\Base\CreatedAtField;
use App\GraphQL\Schema\Fields\Base\UpdatedAtField;
use App\GraphQL\Schema\Fields\Field;
@@ -14,7 +13,7 @@ use App\GraphQL\Schema\Types\Wiki\AnimeType;
use App\GraphQL\Schema\Types\Wiki\StudioType;
use App\Pivots\Wiki\AnimeStudio;
class AnimeStudioType extends PivotType implements SubmitableType
class AnimeStudioType extends PivotType
{
public function description(): string
{
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\GraphQL\Schema\Types\Pivot\Wiki;
use App\Contracts\GraphQL\Types\SubmitableType;
use App\GraphQL\Schema\Fields\Base\CreatedAtField;
use App\GraphQL\Schema\Fields\Base\UpdatedAtField;
use App\GraphQL\Schema\Fields\Field;
@@ -14,7 +13,7 @@ use App\GraphQL\Schema\Types\Wiki\Anime\Theme\AnimeThemeEntryType;
use App\GraphQL\Schema\Types\Wiki\VideoType;
use App\Pivots\Wiki\AnimeThemeEntryVideo;
class AnimeThemeEntryVideoType extends PivotType implements SubmitableType
class AnimeThemeEntryVideoType extends PivotType
{
public function description(): string
{
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\GraphQL\Schema\Types\Pivot\Wiki;
use App\Contracts\GraphQL\Types\SubmitableType;
use App\GraphQL\Schema\Fields\Base\CreatedAtField;
use App\GraphQL\Schema\Fields\Base\UpdatedAtField;
use App\GraphQL\Schema\Fields\Field;
@@ -17,7 +16,7 @@ use App\GraphQL\Schema\Types\Pivot\PivotType;
use App\GraphQL\Schema\Types\Wiki\ArtistType;
use App\Pivots\Wiki\ArtistMember;
class ArtistMemberType extends PivotType implements SubmitableType
class ArtistMemberType extends PivotType
{
public function description(): string
{
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\GraphQL\Schema\Types\Wiki\Anime;
use App\Contracts\GraphQL\Types\SubmitableType;
use App\GraphQL\Schema\Fields\Base\CreatedAtField;
use App\GraphQL\Schema\Fields\Base\DeletedAtField;
use App\GraphQL\Schema\Fields\Base\IdField;
@@ -18,7 +17,7 @@ use App\GraphQL\Schema\Types\EloquentType;
use App\GraphQL\Schema\Types\Wiki\AnimeType;
use App\Models\Wiki\Anime\AnimeSynonym;
class AnimeSynonymType extends EloquentType implements SubmitableType
class AnimeSynonymType extends EloquentType
{
public function description(): string
{
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\GraphQL\Schema\Types\Wiki\Anime;
use App\Contracts\GraphQL\Types\SubmitableType;
use App\GraphQL\Schema\Fields\Base\CreatedAtField;
use App\GraphQL\Schema\Fields\Base\DeletedAtField;
use App\GraphQL\Schema\Fields\Base\IdField;
@@ -24,7 +23,7 @@ use App\GraphQL\Schema\Types\Wiki\SongType;
use App\GraphQL\Schema\Types\Wiki\ThemeGroupType;
use App\Models\Wiki\Anime\AnimeTheme;
class AnimeThemeType extends EloquentType implements SubmitableType
class AnimeThemeType extends EloquentType
{
public function description(): string
{
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\GraphQL\Schema\Types\Wiki\Anime\Theme;
use App\Contracts\GraphQL\Types\SubmitableType;
use App\GraphQL\Schema\Fields\Base\Aggregate\LikesCountField;
use App\GraphQL\Schema\Fields\Base\CreatedAtField;
use App\GraphQL\Schema\Fields\Base\DeletedAtField;
@@ -28,7 +27,7 @@ use App\GraphQL\Schema\Types\Wiki\ExternalResourceType;
use App\GraphQL\Schema\Types\Wiki\VideoType;
use App\Models\Wiki\Anime\Theme\AnimeThemeEntry;
class AnimeThemeEntryType extends EloquentType implements SubmitableType
class AnimeThemeEntryType extends EloquentType
{
public function description(): string
{
+5 -3
View File
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\GraphQL\Schema\Types\Wiki;
use App\Contracts\GraphQL\Types\SubmitableType;
use App\GraphQL\Schema\Fields\Base\CreatedAtField;
use App\GraphQL\Schema\Fields\Base\DeletedAtField;
use App\GraphQL\Schema\Fields\Base\IdUnbindableField;
@@ -13,6 +12,7 @@ use App\GraphQL\Schema\Fields\Field;
use App\GraphQL\Schema\Fields\LocalizedEnumField;
use App\GraphQL\Schema\Fields\Relations\BelongsToManyRelation;
use App\GraphQL\Schema\Fields\Relations\HasManyRelation;
use App\GraphQL\Schema\Fields\Relations\MorphManyRelation;
use App\GraphQL\Schema\Fields\Relations\MorphToManyRelation;
use App\GraphQL\Schema\Fields\Wiki\Anime\AnimeMediaFormatField;
use App\GraphQL\Schema\Fields\Wiki\Anime\AnimeNameField;
@@ -29,7 +29,7 @@ use App\GraphQL\Schema\Types\Wiki\Anime\AnimeSynonymType;
use App\GraphQL\Schema\Types\Wiki\Anime\AnimeThemeType;
use App\Models\Wiki\Anime;
class AnimeType extends EloquentType implements SubmitableType
class AnimeType extends EloquentType
{
public function description(): string
{
@@ -57,7 +57,9 @@ class AnimeType extends EloquentType implements SubmitableType
new UpdatedAtField(),
new DeletedAtField(),
new HasManyRelation(new AnimeSynonymType(), Anime::RELATION_SYNONYMS),
new HasManyRelation(new AnimeSynonymType(), Anime::RELATION_ANIMESYNONYMS)
->deprecate('Use synonyms instead.'),
new MorphManyRelation(new SynonymType(), Anime::RELATION_SYNONYMS),
new HasManyRelation(new AnimeThemeType(), Anime::RELATION_THEMES),
new MorphToManyRelation($this, new ExternalResourceType(), Anime::RELATION_RESOURCES, new ResourceableType()),
new MorphToManyRelation($this, new ImageType(), Anime::RELATION_IMAGES, new ImageableType()),
+1 -2
View File
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\GraphQL\Schema\Types\Wiki;
use App\Contracts\GraphQL\Types\SubmitableType;
use App\GraphQL\Schema\Fields\Base\CreatedAtField;
use App\GraphQL\Schema\Fields\Base\DeletedAtField;
use App\GraphQL\Schema\Fields\Base\IdUnbindableField;
@@ -25,7 +24,7 @@ use App\GraphQL\Schema\Types\Wiki\Song\MembershipType;
use App\GraphQL\Schema\Types\Wiki\Song\PerformanceType;
use App\Models\Wiki\Artist;
class ArtistType extends EloquentType implements SubmitableType
class ArtistType extends EloquentType
{
public function description(): string
{
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\GraphQL\Schema\Types\Wiki;
use App\Contracts\GraphQL\Types\SubmitableType;
use App\GraphQL\Schema\Fields\Base\CreatedAtField;
use App\GraphQL\Schema\Fields\Base\DeletedAtField;
use App\GraphQL\Schema\Fields\Base\IdField;
@@ -19,7 +18,7 @@ use App\GraphQL\Schema\Types\EloquentType;
use App\GraphQL\Schema\Types\Pivot\Morph\ResourceableType;
use App\Models\Wiki\ExternalResource;
class ExternalResourceType extends EloquentType implements SubmitableType
class ExternalResourceType extends EloquentType
{
public function description(): string
{
+1 -2
View File
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\GraphQL\Schema\Types\Wiki;
use App\Contracts\GraphQL\Types\SubmitableType;
use App\GraphQL\Schema\Fields\Base\CreatedAtField;
use App\GraphQL\Schema\Fields\Base\DeletedAtField;
use App\GraphQL\Schema\Fields\Base\IdField;
@@ -19,7 +18,7 @@ use App\GraphQL\Schema\Types\EloquentType;
use App\GraphQL\Schema\Types\Pivot\Morph\ImageableType;
use App\Models\Wiki\Image;
class ImageType extends EloquentType implements SubmitableType
class ImageType extends EloquentType
{
public function description(): string
{
+1 -2
View File
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\GraphQL\Schema\Types\Wiki;
use App\Contracts\GraphQL\Types\SubmitableType;
use App\GraphQL\Schema\Fields\Base\CreatedAtField;
use App\GraphQL\Schema\Fields\Base\DeletedAtField;
use App\GraphQL\Schema\Fields\Base\IdUnbindableField;
@@ -17,7 +16,7 @@ use App\GraphQL\Schema\Types\EloquentType;
use App\GraphQL\Schema\Types\Pivot\Wiki\AnimeSeriesType;
use App\Models\Wiki\Series;
class SeriesType extends EloquentType implements SubmitableType
class SeriesType extends EloquentType
{
public function description(): string
{
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\GraphQL\Schema\Types\Wiki\Song;
use App\Contracts\GraphQL\Types\SubmitableType;
use App\GraphQL\Schema\Fields\Base\CreatedAtField;
use App\GraphQL\Schema\Fields\Base\DeletedAtField;
use App\GraphQL\Schema\Fields\Base\IdField;
@@ -18,7 +17,7 @@ use App\GraphQL\Schema\Types\EloquentType;
use App\GraphQL\Schema\Types\Wiki\ArtistType;
use App\Models\Wiki\Song\Membership;
class MembershipType extends EloquentType implements SubmitableType
class MembershipType extends EloquentType
{
public function description(): string
{
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\GraphQL\Schema\Types\Wiki\Song;
use App\Contracts\GraphQL\Types\SubmitableType;
use App\GraphQL\Schema\Fields\Base\CreatedAtField;
use App\GraphQL\Schema\Fields\Base\DeletedAtField;
use App\GraphQL\Schema\Fields\Base\IdField;
@@ -20,7 +19,7 @@ use App\GraphQL\Schema\Types\Wiki\SongType;
use App\GraphQL\Schema\Unions\PerformanceArtistUnion;
use App\Models\Wiki\Song\Performance;
class PerformanceType extends EloquentType implements SubmitableType
class PerformanceType extends EloquentType
{
public function description(): string
{
+1 -2
View File
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\GraphQL\Schema\Types\Wiki;
use App\Contracts\GraphQL\Types\SubmitableType;
use App\GraphQL\Schema\Fields\Base\CreatedAtField;
use App\GraphQL\Schema\Fields\Base\DeletedAtField;
use App\GraphQL\Schema\Fields\Base\IdField;
@@ -20,7 +19,7 @@ use App\GraphQL\Schema\Types\Wiki\Anime\AnimeThemeType;
use App\GraphQL\Schema\Types\Wiki\Song\PerformanceType;
use App\Models\Wiki\Song;
class SongType extends EloquentType implements SubmitableType
class SongType extends EloquentType
{
public function description(): string
{
+1 -2
View File
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\GraphQL\Schema\Types\Wiki;
use App\Contracts\GraphQL\Types\SubmitableType;
use App\GraphQL\Schema\Fields\Base\CreatedAtField;
use App\GraphQL\Schema\Fields\Base\DeletedAtField;
use App\GraphQL\Schema\Fields\Base\IdUnbindableField;
@@ -20,7 +19,7 @@ use App\GraphQL\Schema\Types\Pivot\Morph\ResourceableType;
use App\GraphQL\Schema\Types\Pivot\Wiki\AnimeStudioType;
use App\Models\Wiki\Studio;
class StudioType extends EloquentType implements SubmitableType
class StudioType extends EloquentType
{
public function description(): string
{
@@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
namespace App\GraphQL\Schema\Types\Wiki;
use App\GraphQL\Schema\Fields\Base\CreatedAtField;
use App\GraphQL\Schema\Fields\Base\DeletedAtField;
use App\GraphQL\Schema\Fields\Base\IdField;
use App\GraphQL\Schema\Fields\Base\UpdatedAtField;
use App\GraphQL\Schema\Fields\Field;
use App\GraphQL\Schema\Fields\LocalizedEnumField;
use App\GraphQL\Schema\Fields\Relations\MorphToRelation;
use App\GraphQL\Schema\Fields\Wiki\Synonym\SynonymTextField;
use App\GraphQL\Schema\Fields\Wiki\Synonym\SynonymTypeField;
use App\GraphQL\Schema\Types\EloquentType;
use App\GraphQL\Schema\Unions\SynonymableUnion;
use App\Models\Wiki\Synonym;
class SynonymType extends EloquentType
{
public function description(): string
{
return "Represents an alternate title or common abbreviation for an entity.\n\nFor example, the anime Bakemonogatari has the synonym \"Monstory\".";
}
/**
* The fields of the type.
*
* @return Field[]
*/
public function fieldClasses(): array
{
return [
new IdField(Synonym::ATTRIBUTE_ID, Synonym::class),
new SynonymTextField(),
new SynonymTypeField(),
new LocalizedEnumField(new SynonymTypeField()),
new CreatedAtField(),
new UpdatedAtField(),
new DeletedAtField(),
new MorphToRelation(new SynonymableUnion(), Synonym::RELATION_SYNONYMABLE)
->nonNullable(),
];
}
}
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\GraphQL\Schema\Types\Wiki;
use App\Contracts\GraphQL\Types\SubmitableType;
use App\GraphQL\Schema\Fields\Base\CreatedAtField;
use App\GraphQL\Schema\Fields\Base\DeletedAtField;
use App\GraphQL\Schema\Fields\Base\IdField;
@@ -17,7 +16,7 @@ use App\GraphQL\Schema\Types\EloquentType;
use App\GraphQL\Schema\Types\Wiki\Anime\AnimeThemeType;
use App\Models\Wiki\Group;
class ThemeGroupType extends EloquentType implements SubmitableType
class ThemeGroupType extends EloquentType
{
public function description(): string
{
+1 -2
View File
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace App\GraphQL\Schema\Types\Wiki;
use App\Contracts\GraphQL\Types\SubmitableType;
use App\GraphQL\Schema\Fields\Base\CreatedAtField;
use App\GraphQL\Schema\Fields\Base\DeletedAtField;
use App\GraphQL\Schema\Fields\Base\IdField;
@@ -38,7 +37,7 @@ use App\GraphQL\Schema\Types\Wiki\Anime\Theme\AnimeThemeEntryType;
use App\GraphQL\Schema\Types\Wiki\Video\VideoScriptType;
use App\Models\Wiki\Video;
class VideoType extends EloquentType implements SubmitableType
class VideoType extends EloquentType
{
public function description(): string
{
@@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace App\GraphQL\Schema\Unions;
use App\GraphQL\Schema\Types\BaseType;
use App\GraphQL\Schema\Types\Wiki\AnimeType;
class SynonymableUnion extends BaseUnion
{
public function description(): string
{
return 'Represents the types that have synonyms';
}
/**
* The types that this union can resolve to.
*
* @return BaseType[]
*/
public function baseTypes(): array
{
return [
new AnimeType(),
];
}
}
@@ -14,7 +14,7 @@ use App\Models\Wiki\Anime\AnimeSynonym;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
class SynonymAnimeIdField extends Field implements CreatableField, SelectableField
class AnimeSynonymAnimeIdField extends Field implements CreatableField, SelectableField
{
public function __construct(Schema $schema)
{
@@ -11,7 +11,7 @@ use App\Http\Api\Schema\Schema;
use App\Models\Wiki\Anime\AnimeSynonym;
use Illuminate\Http\Request;
class SynonymTextField extends StringField implements CreatableField, UpdatableField
class AnimeSynonymTextField extends StringField implements CreatableField, UpdatableField
{
public function __construct(Schema $schema)
{
@@ -13,7 +13,7 @@ use App\Models\Wiki\Anime\AnimeSynonym;
use Illuminate\Http\Request;
use Illuminate\Validation\Rules\Enum;
class SynonymTypeField extends EnumField implements CreatableField, UpdatableField
class AnimeSynonymTypeField extends EnumField implements CreatableField, UpdatableField
{
public function __construct(Schema $schema)
{
@@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace App\Http\Api\Field\Wiki\Synonym;
use App\Contracts\Http\Api\Field\CreatableField;
use App\Contracts\Http\Api\Field\SelectableField;
use App\Http\Api\Field\Field;
use App\Http\Api\Query\Query;
use App\Http\Api\Schema\Schema;
use App\Models\Wiki\Anime;
use App\Models\Wiki\Synonym;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
class SynonymSynonymableIdField extends Field implements CreatableField, SelectableField
{
public function __construct(Schema $schema)
{
parent::__construct($schema, Synonym::ATTRIBUTE_SYNONYMABLE_ID);
}
public function getCreationRules(Request $request): array
{
return [
'required',
'integer',
Rule::exists(Anime::class, Anime::ATTRIBUTE_ID),
];
}
public function shouldSelect(Query $query, Schema $schema): bool
{
// Needed to match synonymable relation.
return true;
}
}
@@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace App\Http\Api\Field\Wiki\Synonym;
use App\Contracts\Http\Api\Field\CreatableField;
use App\Contracts\Http\Api\Field\SelectableField;
use App\Http\Api\Field\Field;
use App\Http\Api\Query\Query;
use App\Http\Api\Schema\Schema;
use App\Models\Wiki\Synonym;
use Illuminate\Http\Request;
class SynonymSynonymableTypeField extends Field implements CreatableField, SelectableField
{
public function __construct(Schema $schema)
{
parent::__construct($schema, Synonym::ATTRIBUTE_SYNONYMABLE_TYPE);
}
public function getCreationRules(Request $request): array
{
return [
'required',
'string',
];
}
public function shouldSelect(Query $query, Schema $schema): bool
{
// Needed to match synonymable relation.
return true;
}
}
@@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
namespace App\Http\Api\Field\Wiki\Synonym;
use App\Contracts\Http\Api\Field\CreatableField;
use App\Contracts\Http\Api\Field\UpdatableField;
use App\Http\Api\Field\StringField;
use App\Http\Api\Schema\Schema;
use App\Models\Wiki\Synonym;
use Illuminate\Http\Request;
class SynonymTextField extends StringField implements CreatableField, UpdatableField
{
public function __construct(Schema $schema)
{
parent::__construct($schema, Synonym::ATTRIBUTE_TEXT);
}
public function getCreationRules(Request $request): array
{
return [
'required',
'string',
'max:192',
];
}
public function getUpdateRules(Request $request): array
{
return [
'sometimes',
'required',
'string',
'max:192',
];
}
}
@@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
namespace App\Http\Api\Field\Wiki\Synonym;
use App\Contracts\Http\Api\Field\CreatableField;
use App\Contracts\Http\Api\Field\UpdatableField;
use App\Enums\Models\Wiki\SynonymType;
use App\Http\Api\Field\EnumField;
use App\Http\Api\Schema\Schema;
use App\Models\Wiki\Synonym;
use Illuminate\Http\Request;
use Illuminate\Validation\Rules\Enum;
class SynonymTypeField extends EnumField implements CreatableField, UpdatableField
{
public function __construct(Schema $schema)
{
parent::__construct($schema, Synonym::ATTRIBUTE_TYPE, SynonymType::class);
}
public function getCreationRules(Request $request): array
{
return [
'required',
new Enum(SynonymType::class),
];
}
public function getUpdateRules(Request $request): array
{
return [
'sometimes',
'required',
new Enum(SynonymType::class),
];
}
}
@@ -7,21 +7,20 @@ namespace App\Http\Api\Schema\Wiki\Anime;
use App\Contracts\Http\Api\Schema\SearchableSchema;
use App\Http\Api\Field\Base\IdField;
use App\Http\Api\Field\Field;
use App\Http\Api\Field\Wiki\Anime\Synonym\SynonymAnimeIdField;
use App\Http\Api\Field\Wiki\Anime\Synonym\SynonymTextField;
use App\Http\Api\Field\Wiki\Anime\Synonym\SynonymTypeField;
use App\Http\Api\Field\Wiki\Anime\Synonym\AnimeSynonymAnimeIdField;
use App\Http\Api\Field\Wiki\Anime\Synonym\AnimeSynonymTextField;
use App\Http\Api\Field\Wiki\Anime\Synonym\AnimeSynonymTypeField;
use App\Http\Api\Include\AllowedInclude;
use App\Http\Api\Schema\EloquentSchema;
use App\Http\Api\Schema\Wiki\AnimeSchema;
use App\Http\Resources\Wiki\Anime\Resource\SynonymJsonResource;
use App\Http\Resources\Wiki\Anime\Resource\AnimeSynonymJsonResource;
use App\Models\Wiki\Anime\AnimeSynonym;
use Illuminate\Database\Eloquent\Model;
class SynonymSchema extends EloquentSchema implements SearchableSchema
class AnimeSynonymSchema extends EloquentSchema implements SearchableSchema
{
public function type(): string
{
return SynonymJsonResource::$wrap;
return AnimeSynonymJsonResource::$wrap;
}
/**
@@ -43,18 +42,10 @@ class SynonymSchema extends EloquentSchema implements SearchableSchema
parent::fields(),
[
new IdField($this, AnimeSynonym::ATTRIBUTE_ID),
new SynonymTextField($this),
new SynonymTypeField($this),
new SynonymAnimeIdField($this),
new AnimeSynonymTextField($this),
new AnimeSynonymTypeField($this),
new AnimeSynonymAnimeIdField($this),
],
);
}
/**
* Get the model of the schema.
*/
public function model(): AnimeSynonym
{
return new AnimeSynonym();
}
}
+2 -1
View File
@@ -18,7 +18,7 @@ use App\Http\Api\Include\AllowedInclude;
use App\Http\Api\Schema\Auth\UserSchema;
use App\Http\Api\Schema\EloquentSchema;
use App\Http\Api\Schema\Pivot\Morph\ResourceableSchema;
use App\Http\Api\Schema\Wiki\Anime\SynonymSchema;
use App\Http\Api\Schema\Wiki\Anime\AnimeSynonymSchema;
use App\Http\Api\Schema\Wiki\Anime\Theme\EntrySchema;
use App\Http\Api\Schema\Wiki\Anime\ThemeSchema;
use App\Http\Api\Schema\Wiki\Video\ScriptSchema;
@@ -58,6 +58,7 @@ class AnimeSchema extends EloquentSchema implements InteractsWithPivots, Searcha
new AllowedInclude(new SeriesSchema(), Anime::RELATION_SERIES),
new AllowedInclude(new SongSchema(), Anime::RELATION_SONG),
new AllowedInclude(new StudioSchema(), Anime::RELATION_STUDIOS),
new AllowedInclude(new AnimeSynonymSchema(), Anime::RELATION_ANIMESYNONYMS),
new AllowedInclude(new SynonymSchema(), Anime::RELATION_SYNONYMS),
new AllowedInclude(new ThemeSchema(), Anime::RELATION_THEMES),
new AllowedInclude(new VideoSchema(), Anime::RELATION_VIDEOS),
+2 -2
View File
@@ -11,7 +11,7 @@ use App\Http\Api\Field\Wiki\Series\SeriesNameField;
use App\Http\Api\Field\Wiki\Series\SeriesSlugField;
use App\Http\Api\Include\AllowedInclude;
use App\Http\Api\Schema\EloquentSchema;
use App\Http\Api\Schema\Wiki\Anime\SynonymSchema;
use App\Http\Api\Schema\Wiki\Anime\AnimeSynonymSchema;
use App\Http\Resources\Wiki\Resource\SeriesJsonResource;
use App\Models\Wiki\Series;
@@ -35,7 +35,7 @@ class SeriesSchema extends EloquentSchema implements SearchableSchema
new AllowedInclude(new VideoSchema(), 'anime.animethemes.animethemeentries.videos'),
new AllowedInclude(new GroupSchema(), 'anime.animethemes.group'),
new AllowedInclude(new SongSchema(), 'anime.animethemes.song'),
new AllowedInclude(new SynonymSchema(), 'anime.animesynonyms'),
new AllowedInclude(new AnimeSynonymSchema(), 'anime.animesynonyms'),
]);
}
@@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
namespace App\Http\Api\Schema\Wiki;
use App\Contracts\Http\Api\Schema\SearchableSchema;
use App\Http\Api\Field\Base\IdField;
use App\Http\Api\Field\Field;
use App\Http\Api\Field\Wiki\Synonym\SynonymSynonymableIdField;
use App\Http\Api\Field\Wiki\Synonym\SynonymSynonymableTypeField;
use App\Http\Api\Field\Wiki\Synonym\SynonymTextField;
use App\Http\Api\Field\Wiki\Synonym\SynonymTypeField;
use App\Http\Api\Include\AllowedInclude;
use App\Http\Api\Schema\EloquentSchema;
use App\Http\Resources\Wiki\Resource\SynonymJsonResource;
use App\Models\Wiki\Synonym;
class SynonymSchema extends EloquentSchema implements SearchableSchema
{
public function type(): string
{
return SynonymJsonResource::$wrap;
}
/**
* @return AllowedInclude[]
*/
public function allowedIncludes(): array
{
return $this->withIntermediatePaths();
}
/**
* @return Field[]
*/
public function fields(): array
{
return array_merge(
parent::fields(),
[
new IdField($this, Synonym::ATTRIBUTE_ID),
new SynonymTextField($this),
new SynonymTypeField($this),
new SynonymSynonymableTypeField($this),
new SynonymSynonymableIdField($this),
],
);
}
}
@@ -17,19 +17,19 @@ use App\Http\Requests\Api\IndexRequest;
use App\Http\Requests\Api\ShowRequest;
use App\Http\Requests\Api\StoreRequest;
use App\Http\Requests\Api\UpdateRequest;
use App\Http\Resources\Wiki\Anime\Collection\SynonymCollection;
use App\Http\Resources\Wiki\Anime\Resource\SynonymJsonResource;
use App\Http\Resources\Wiki\Anime\Collection\AnimeSynonymCollection;
use App\Http\Resources\Wiki\Anime\Resource\AnimeSynonymJsonResource;
use App\Models\Wiki\Anime\AnimeSynonym;
use Illuminate\Http\JsonResponse;
class SynonymController extends BaseController
class AnimeSynonymController extends BaseController
{
public function __construct()
{
parent::__construct(AnimeSynonym::class, 'animesynonym');
}
public function index(IndexRequest $request, IndexAction $action): SynonymCollection
public function index(IndexRequest $request, IndexAction $action): AnimeSynonymCollection
{
$query = new Query($request->validated());
@@ -37,47 +37,47 @@ class SynonymController extends BaseController
? $action->search($query, $request->schema())
: $action->index(AnimeSynonym::query(), $query, $request->schema());
return new SynonymCollection($synonyms, $query);
return new AnimeSynonymCollection($synonyms, $query);
}
/**
* @param StoreAction<AnimeSynonym> $action
*/
public function store(StoreRequest $request, StoreAction $action): SynonymJsonResource
public function store(StoreRequest $request, StoreAction $action): AnimeSynonymJsonResource
{
$synonym = $action->store(AnimeSynonym::query(), $request->validated());
return new SynonymJsonResource($synonym, new Query());
return new AnimeSynonymJsonResource($synonym, new Query());
}
public function show(ShowRequest $request, AnimeSynonym $animesynonym, ShowAction $action): SynonymJsonResource
public function show(ShowRequest $request, AnimeSynonym $animesynonym, ShowAction $action): AnimeSynonymJsonResource
{
$query = new Query($request->validated());
$show = $action->show($animesynonym, $query, $request->schema());
return new SynonymJsonResource($show, $query);
return new AnimeSynonymJsonResource($show, $query);
}
public function update(UpdateRequest $request, AnimeSynonym $animesynonym, UpdateAction $action): SynonymJsonResource
public function update(UpdateRequest $request, AnimeSynonym $animesynonym, UpdateAction $action): AnimeSynonymJsonResource
{
$updated = $action->update($animesynonym, $request->validated());
return new SynonymJsonResource($updated, new Query());
return new AnimeSynonymJsonResource($updated, new Query());
}
public function destroy(AnimeSynonym $animesynonym, DestroyAction $action): SynonymJsonResource
public function destroy(AnimeSynonym $animesynonym, DestroyAction $action): AnimeSynonymJsonResource
{
$deleted = $action->destroy($animesynonym);
return new SynonymJsonResource($deleted, new Query());
return new AnimeSynonymJsonResource($deleted, new Query());
}
public function restore(AnimeSynonym $animesynonym, RestoreAction $action): SynonymJsonResource
public function restore(AnimeSynonym $animesynonym, RestoreAction $action): AnimeSynonymJsonResource
{
$restored = $action->restore($animesynonym);
return new SynonymJsonResource($restored, new Query());
return new AnimeSynonymJsonResource($restored, new Query());
}
public function forceDelete(AnimeSynonym $animesynonym, ForceDeleteAction $action): JsonResponse
@@ -0,0 +1,91 @@
<?php
declare(strict_types=1);
namespace App\Http\Controllers\Api\Wiki;
use App\Actions\Http\Api\DestroyAction;
use App\Actions\Http\Api\ForceDeleteAction;
use App\Actions\Http\Api\IndexAction;
use App\Actions\Http\Api\RestoreAction;
use App\Actions\Http\Api\ShowAction;
use App\Actions\Http\Api\StoreAction;
use App\Actions\Http\Api\UpdateAction;
use App\Http\Api\Query\Query;
use App\Http\Controllers\Api\BaseController;
use App\Http\Requests\Api\IndexRequest;
use App\Http\Requests\Api\ShowRequest;
use App\Http\Requests\Api\StoreRequest;
use App\Http\Requests\Api\UpdateRequest;
use App\Http\Resources\Wiki\Collection\SynonymCollection;
use App\Http\Resources\Wiki\Resource\SynonymJsonResource;
use App\Models\Wiki\Synonym;
use Illuminate\Http\JsonResponse;
class SynonymController extends BaseController
{
public function __construct()
{
parent::__construct(Synonym::class, 'synonym');
}
public function index(IndexRequest $request, IndexAction $action): SynonymCollection
{
$query = new Query($request->validated());
$synonyms = $query->hasSearchCriteria()
? $action->search($query, $request->schema())
: $action->index(Synonym::query(), $query, $request->schema());
return new SynonymCollection($synonyms, $query);
}
/**
* @param StoreAction<Synonym> $action
*/
public function store(StoreRequest $request, StoreAction $action): SynonymJsonResource
{
$synonym = $action->store(Synonym::query(), $request->validated());
return new SynonymJsonResource($synonym, new Query());
}
public function show(ShowRequest $request, Synonym $synonym, ShowAction $action): SynonymJsonResource
{
$query = new Query($request->validated());
$show = $action->show($synonym, $query, $request->schema());
return new SynonymJsonResource($show, $query);
}
public function update(UpdateRequest $request, Synonym $synonym, UpdateAction $action): SynonymJsonResource
{
$updated = $action->update($synonym, $request->validated());
return new SynonymJsonResource($updated, new Query());
}
public function destroy(Synonym $synonym, DestroyAction $action): SynonymJsonResource
{
$deleted = $action->destroy($synonym);
return new SynonymJsonResource($deleted, new Query());
}
public function restore(Synonym $synonym, RestoreAction $action): SynonymJsonResource
{
$restored = $action->restore($synonym);
return new SynonymJsonResource($restored, new Query());
}
public function forceDelete(Synonym $synonym, ForceDeleteAction $action): JsonResponse
{
$message = $action->forceDelete($synonym);
return new JsonResponse([
'message' => $message,
]);
}
}
@@ -5,11 +5,11 @@ declare(strict_types=1);
namespace App\Http\Resources\Wiki\Anime\Collection;
use App\Http\Resources\BaseCollection;
use App\Http\Resources\Wiki\Anime\Resource\SynonymJsonResource;
use App\Http\Resources\Wiki\Anime\Resource\AnimeSynonymJsonResource;
use App\Models\Wiki\Anime\AnimeSynonym;
use Illuminate\Http\Request;
class SynonymCollection extends BaseCollection
class AnimeSynonymCollection extends BaseCollection
{
/**
* The "data" wrapper that should be applied.
@@ -27,7 +27,7 @@ class SynonymCollection extends BaseCollection
public function toArray(Request $request): array
{
return $this->collection->map(
fn (AnimeSynonym $synonym): SynonymJsonResource => new SynonymJsonResource($synonym, $this->query)
fn (AnimeSynonym $synonym): AnimeSynonymJsonResource => new AnimeSynonymJsonResource($synonym, $this->query)
)->all();
}
}
@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace App\Http\Resources\Wiki\Anime\Resource;
use App\Http\Api\Schema\Schema;
use App\Http\Api\Schema\Wiki\Anime\AnimeSynonymSchema;
use App\Http\Resources\BaseJsonResource;
class AnimeSynonymJsonResource extends BaseJsonResource
{
/**
* The "data" wrapper that should be applied.
*
* @var string|null
*/
public static $wrap = 'animesynonym';
/**
* Get the resource schema.
*/
protected function schema(): Schema
{
return new AnimeSynonymSchema();
}
}
@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace App\Http\Resources\Wiki\Collection;
use App\Http\Resources\BaseCollection;
use App\Http\Resources\Wiki\Resource\SynonymJsonResource;
use App\Models\Wiki\Synonym;
use Illuminate\Http\Request;
class SynonymCollection extends BaseCollection
{
/**
* The "data" wrapper that should be applied.
*
* @var string|null
*/
public static $wrap = 'synonyms';
/**
* Transform the resource into a JSON array.
*
*
* @noinspection PhpMissingParentCallCommonInspection
*/
public function toArray(Request $request): array
{
return $this->collection->map(
fn (Synonym $synonym): SynonymJsonResource => new SynonymJsonResource($synonym, $this->query)
)->all();
}
}
@@ -2,10 +2,10 @@
declare(strict_types=1);
namespace App\Http\Resources\Wiki\Anime\Resource;
namespace App\Http\Resources\Wiki\Resource;
use App\Http\Api\Schema\Schema;
use App\Http\Api\Schema\Wiki\Anime\SynonymSchema;
use App\Http\Api\Schema\Wiki\SynonymSchema;
use App\Http\Resources\BaseJsonResource;
class SynonymJsonResource extends BaseJsonResource
@@ -15,7 +15,7 @@ class SynonymJsonResource extends BaseJsonResource
*
* @var string|null
*/
public static $wrap = 'animesynonym';
public static $wrap = 'synonym';
/**
* Get the resource schema.
@@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace App\Listeners\Wiki;
use App\Contracts\Events\UpdateAnimeSynonymsEvent;
use Illuminate\Contracts\Events\ShouldHandleEventsAfterCommit;
class UpdateAnimeSynonyms implements ShouldHandleEventsAfterCommit
{
public function handle(UpdateAnimeSynonymsEvent $event): void
{
$event->updateAnimeSynonyms();
}
}
+19 -4
View File
@@ -8,6 +8,7 @@ use App\Concerns\Models\SoftDeletes;
use App\Concerns\Models\Submitable;
use App\Contracts\Models\HasImages;
use App\Contracts\Models\HasResources;
use App\Contracts\Models\HasSynonyms;
use App\Contracts\Models\SoftDeletable;
use App\Enums\Models\Wiki\AnimeMediaFormat;
use App\Enums\Models\Wiki\AnimeSeason;
@@ -28,12 +29,14 @@ use App\Pivots\Morph\Resourceable;
use App\Pivots\Wiki\AnimeSeries;
use App\Pivots\Wiki\AnimeStudio;
use Database\Factories\Wiki\AnimeFactory;
use Deprecated;
use Elastic\ScoutDriverPlus\Searchable;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\Relations\MorphToMany;
use Illuminate\Support\Collection;
use OwenIt\Auditing\Auditable as HasAudits;
@@ -41,7 +44,6 @@ use OwenIt\Auditing\Contracts\Auditable;
/**
* @property int $anime_id
* @property Collection<int, AnimeSynonym> $animesynonyms
* @property Collection<int, AnimeTheme> $animethemes
* @property DiscordThread|null $discordthread
* @property Collection<int, ExternalEntry> $externalentries
@@ -53,12 +55,13 @@ use OwenIt\Auditing\Contracts\Auditable;
* @property Collection<int, Series> $series
* @property string $slug
* @property Collection<int, Studio> $studios
* @property Collection<int, Synonym> $synonyms
* @property string|null $synopsis
* @property int|null $year
*
* @method static AnimeFactory factory(...$parameters)
*/
class Anime extends BaseModel implements Auditable, HasImages, HasResources, SoftDeletable
class Anime extends BaseModel implements Auditable, HasImages, HasResources, HasSynonyms, SoftDeletable
{
use HasAudits;
use HasFactory;
@@ -88,7 +91,8 @@ class Anime extends BaseModel implements Auditable, HasImages, HasResources, Sof
final public const string RELATION_SERIES = 'series';
final public const string RELATION_SONG = 'animethemes.song';
final public const string RELATION_STUDIOS = 'studios';
final public const string RELATION_SYNONYMS = 'animesynonyms';
final public const string RELATION_ANIMESYNONYMS = 'animesynonyms';
final public const string RELATION_SYNONYMS = 'synonyms';
final public const string RELATION_THEMES = 'animethemes';
final public const string RELATION_VIDEOS = 'animethemes.animethemeentries.videos';
@@ -163,7 +167,7 @@ class Anime extends BaseModel implements Auditable, HasImages, HasResources, Sof
public function toSearchableArray(): array
{
$array = $this->toArray();
$array['synonyms'] = $this->animesynonyms->toArray();
$array['synonyms'] = $this->synonyms->toArray();
return $array;
}
@@ -191,11 +195,22 @@ class Anime extends BaseModel implements Auditable, HasImages, HasResources, Sof
/**
* @return HasMany<AnimeSynonym, $this>
*/
#[Deprecated('Use synonyms() instead.')]
public function animesynonyms(): HasMany
{
return $this->hasMany(AnimeSynonym::class, AnimeSynonym::ATTRIBUTE_ANIME);
}
/**
* Get the synonyms for the owner model.
*
* @return MorphMany<Synonym, $this>
*/
public function synonyms(): MorphMany
{
return $this->morphMany(Synonym::class, Synonym::RELATION_SYNONYMABLE);
}
/**
* @return HasOne<DiscordThread, $this>
*/
+1 -20
View File
@@ -8,13 +8,8 @@ use App\Concerns\Models\SoftDeletes;
use App\Concerns\Models\Submitable;
use App\Contracts\Models\SoftDeletable;
use App\Enums\Models\Wiki\AnimeSynonymType;
use App\Events\Wiki\Anime\Synonym\SynonymCreated;
use App\Events\Wiki\Anime\Synonym\SynonymDeleted;
use App\Events\Wiki\Anime\Synonym\SynonymRestored;
use App\Events\Wiki\Anime\Synonym\SynonymUpdated;
use App\Models\BaseModel;
use App\Models\Wiki\Anime;
use Database\Factories\Wiki\Anime\AnimeSynonymFactory;
use Elastic\ScoutDriverPlus\Searchable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@@ -28,7 +23,7 @@ use OwenIt\Auditing\Contracts\Auditable;
* @property string|null $text
* @property AnimeSynonymType $type
*
* @method static AnimeSynonymFactory factory(...$parameters)
* @deprecated Use Synonym instead.
*/
class AnimeSynonym extends BaseModel implements Auditable, SoftDeletable
{
@@ -74,20 +69,6 @@ class AnimeSynonym extends BaseModel implements Auditable, SoftDeletable
AnimeSynonym::ATTRIBUTE_TYPE,
];
/**
* The event map for the model.
*
* Allows for object-based events for native Eloquent events.
*
* @var array<string, class-string>
*/
protected $dispatchesEvents = [
'created' => SynonymCreated::class,
'deleted' => SynonymDeleted::class,
'restored' => SynonymRestored::class,
'updated' => SynonymUpdated::class,
];
/**
* Get the attributes that should be cast.
*
+123
View File
@@ -0,0 +1,123 @@
<?php
declare(strict_types=1);
namespace App\Models\Wiki;
use App\Concerns\Models\SoftDeletes;
use App\Concerns\Models\Submitable;
use App\Contracts\Models\HasSynonyms;
use App\Contracts\Models\Nameable;
use App\Contracts\Models\SoftDeletable;
use App\Enums\Models\Wiki\SynonymType;
use App\Events\Wiki\Synonym\SynonymCreated;
use App\Events\Wiki\Synonym\SynonymDeleted;
use App\Events\Wiki\Synonym\SynonymRestored;
use App\Events\Wiki\Synonym\SynonymUpdated;
use App\Models\BaseModel;
use Database\Factories\Wiki\SynonymFactory;
use Elastic\ScoutDriverPlus\Searchable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use OwenIt\Auditing\Auditable as HasAudits;
use OwenIt\Auditing\Contracts\Auditable;
/**
* @property int $synonym_id
* @property Model&Nameable&HasSynonyms $synonymable
* @property string $synonymable_type
* @property int $synonymable_id
* @property string $text
* @property SynonymType $type
*
* @method static SynonymFactory factory(...$parameters)
*/
class Synonym extends BaseModel implements Auditable, SoftDeletable
{
use HasAudits;
use HasFactory;
use Searchable;
use SoftDeletes;
use Submitable;
final public const string TABLE = 'synonyms';
final public const string ATTRIBUTE_ID = 'synonym_id';
final public const string ATTRIBUTE_SYNONYMABLE_TYPE = 'synonymable_type';
final public const string ATTRIBUTE_SYNONYMABLE_ID = 'synonymable_id';
final public const string ATTRIBUTE_TEXT = 'text';
final public const string ATTRIBUTE_TYPE = 'type';
final public const string RELATION_SYNONYMABLE = 'synonymable';
/**
* The table associated with the model.
*
* @var string
*/
protected $table = Synonym::TABLE;
/**
* The primary key associated with the table.
*
* @var string
*/
protected $primaryKey = Synonym::ATTRIBUTE_ID;
/**
* The attributes that are mass assignable.
*
* @var list<string>
*/
protected $fillable = [
Synonym::ATTRIBUTE_SYNONYMABLE_TYPE,
Synonym::ATTRIBUTE_SYNONYMABLE_ID,
Synonym::ATTRIBUTE_TEXT,
Synonym::ATTRIBUTE_TYPE,
];
/**
* The event map for the model.
*
* Allows for object-based events for native Eloquent events.
*
* @var array<string, class-string>
*/
protected $dispatchesEvents = [
'created' => SynonymCreated::class,
'deleted' => SynonymDeleted::class,
'restored' => SynonymRestored::class,
'updated' => SynonymUpdated::class,
];
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
Synonym::ATTRIBUTE_TYPE => SynonymType::class,
];
}
public function getName(): string
{
return $this->text;
}
public function getSubtitle(): string
{
return $this->synonymable->getName();
}
/**
* @return MorphTo<Model, $this>
*/
public function synonymable(): MorphTo
{
return $this->morphTo();
}
}
+9
View File
@@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
namespace App\Policies\Wiki;
use App\Policies\BasePolicy;
class SynonymPolicy extends BasePolicy {}
+2
View File
@@ -17,6 +17,7 @@ use App\Enums\Models\Wiki\AnimeSeason;
use App\Enums\Models\Wiki\AnimeSynonymType;
use App\Enums\Models\Wiki\ImageFacet;
use App\Enums\Models\Wiki\ResourceSite;
use App\Enums\Models\Wiki\SynonymType;
use App\Enums\Models\Wiki\ThemeType;
use App\Enums\Models\Wiki\VideoOverlap;
use App\Enums\Models\Wiki\VideoSource;
@@ -59,6 +60,7 @@ class GraphQLServiceProvider extends ServiceProvider
GraphQL::addType(new EnumType(AnimeSynonymType::class));
GraphQL::addType(new EnumType(ImageFacet::class));
GraphQL::addType(new EnumType(ResourceSite::class));
GraphQL::addType(new EnumType(SynonymType::class));
GraphQL::addType(new EnumType(ThemeType::class));
GraphQL::addType(new EnumType(VideoOverlap::class));
GraphQL::addType(new EnumType(VideoSource::class));
@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace App\Scout\Elasticsearch\Api\Query\Wiki;
use App\Models\Wiki\Synonym;
use App\Scout\Elasticsearch\Api\Query\ElasticQuery;
use App\Search\Criteria;
use Elastic\ScoutDriverPlus\Builders\SearchParametersBuilder;
use Elastic\ScoutDriverPlus\Support\Query;
class SynonymQuery extends ElasticQuery
{
public function build(Criteria $criteria): SearchParametersBuilder
{
$query = Query::bool()
->mustRaw([
'dis_max' => [
'queries' => [
[
'bool' => [
'should' => $this->createTextQuery('text', $criteria->getTerm()),
],
],
],
],
]);
return Synonym::searchQuery($query);
}
}
@@ -5,7 +5,7 @@ declare(strict_types=1);
namespace App\Scout\Elasticsearch\Api\Schema\Wiki\Anime;
use App\Http\Api\Include\AllowedInclude;
use App\Http\Resources\Wiki\Anime\Resource\SynonymJsonResource;
use App\Http\Resources\Wiki\Anime\Resource\AnimeSynonymJsonResource;
use App\Models\Wiki\Anime\AnimeSynonym;
use App\Scout\Elasticsearch\Api\Field\Base\IdField;
use App\Scout\Elasticsearch\Api\Field\Field;
@@ -14,11 +14,11 @@ use App\Scout\Elasticsearch\Api\Field\Wiki\Anime\Synonym\SynonymTypeField;
use App\Scout\Elasticsearch\Api\Schema\Schema;
use App\Scout\Elasticsearch\Api\Schema\Wiki\AnimeSchema;
class SynonymSchema extends Schema
class AnimeSynonymSchema extends Schema
{
public function type(): string
{
return SynonymJsonResource::$wrap;
return AnimeSynonymJsonResource::$wrap;
}
/**
@@ -45,9 +45,4 @@ class SynonymSchema extends Schema
],
);
}
public function model(): AnimeSynonym
{
return new AnimeSynonym();
}
}
@@ -21,7 +21,7 @@ use App\Scout\Elasticsearch\Api\Field\Wiki\Anime\AnimeSlugField;
use App\Scout\Elasticsearch\Api\Field\Wiki\Anime\AnimeSynopsisField;
use App\Scout\Elasticsearch\Api\Field\Wiki\Anime\AnimeYearField;
use App\Scout\Elasticsearch\Api\Schema\Schema;
use App\Scout\Elasticsearch\Api\Schema\Wiki\Anime\SynonymSchema;
use App\Scout\Elasticsearch\Api\Schema\Wiki\Anime\AnimeSynonymSchema;
use App\Scout\Elasticsearch\Api\Schema\Wiki\Anime\Theme\EntrySchema;
use App\Scout\Elasticsearch\Api\Schema\Wiki\Anime\ThemeSchema;
@@ -48,7 +48,7 @@ class AnimeSchema extends Schema
new AllowedInclude(new SeriesSchema(), Anime::RELATION_SERIES),
new AllowedInclude(new SongSchema(), Anime::RELATION_SONG),
new AllowedInclude(new StudioSchema(), Anime::RELATION_STUDIOS),
new AllowedInclude(new SynonymSchema(), Anime::RELATION_SYNONYMS),
new AllowedInclude(new AnimeSynonymSchema(), Anime::RELATION_ANIMESYNONYMS),
new AllowedInclude(new ThemeSchema(), Anime::RELATION_THEMES),
new AllowedInclude(new VideoSchema(), Anime::RELATION_VIDEOS),
]);
+5 -2
View File
@@ -14,10 +14,11 @@ use App\Models\Wiki\Artist;
use App\Models\Wiki\Series;
use App\Models\Wiki\Song;
use App\Models\Wiki\Studio;
use App\Models\Wiki\Synonym;
use App\Models\Wiki\Video;
use App\Scout\Elasticsearch\Api\Query\ElasticQuery;
use App\Scout\Elasticsearch\Api\Query\List\PlaylistQuery;
use App\Scout\Elasticsearch\Api\Query\Wiki\Anime\SynonymQuery;
use App\Scout\Elasticsearch\Api\Query\Wiki\Anime\SynonymQuery as AnimeSynonymQuery;
use App\Scout\Elasticsearch\Api\Query\Wiki\Anime\Theme\EntryQuery;
use App\Scout\Elasticsearch\Api\Query\Wiki\Anime\ThemeQuery;
use App\Scout\Elasticsearch\Api\Query\Wiki\AnimeQuery;
@@ -25,6 +26,7 @@ use App\Scout\Elasticsearch\Api\Query\Wiki\ArtistQuery;
use App\Scout\Elasticsearch\Api\Query\Wiki\SeriesQuery;
use App\Scout\Elasticsearch\Api\Query\Wiki\SongQuery;
use App\Scout\Elasticsearch\Api\Query\Wiki\StudioQuery;
use App\Scout\Elasticsearch\Api\Query\Wiki\SynonymQuery;
use App\Scout\Elasticsearch\Api\Query\Wiki\VideoQuery;
use App\Search\Criteria;
use Closure;
@@ -137,13 +139,14 @@ class ElasticsearchDriver implements SearchDriver
return match ($model) {
Playlist::class => new PlaylistQuery(),
AnimeThemeEntry::class => new EntryQuery(),
AnimeSynonym::class => new SynonymQuery(),
AnimeSynonym::class => new AnimeSynonymQuery(),
AnimeTheme::class => new ThemeQuery(),
Anime::class => new AnimeQuery(),
Artist::class => new ArtistQuery(),
Series::class => new SeriesQuery(),
Song::class => new SongQuery(),
Studio::class => new StudioQuery(),
Synonym::class => new SynonymQuery(),
Video::class => new VideoQuery(),
default => throw new RuntimeException("No ElasticQuery defined for model: {$model}"),
};
@@ -1,41 +0,0 @@
<?php
declare(strict_types=1);
namespace Database\Factories\Wiki\Anime;
use App\Enums\Models\Wiki\AnimeSynonymType;
use App\Models\Wiki\Anime\AnimeSynonym;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Arr;
/**
* @method AnimeSynonym createOne($attributes = [])
* @method AnimeSynonym makeOne($attributes = [])
*
* @extends Factory<AnimeSynonym>
*/
class AnimeSynonymFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var class-string<AnimeSynonym>
*/
protected $model = AnimeSynonym::class;
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
$type = Arr::random(AnimeSynonymType::cases());
return [
AnimeSynonym::ATTRIBUTE_TEXT => fake()->words(3, true),
AnimeSynonym::ATTRIBUTE_TYPE => $type->value,
];
}
}
-6
View File
@@ -7,7 +7,6 @@ namespace Database\Factories\Wiki;
use App\Enums\Models\Wiki\AnimeMediaFormat;
use App\Enums\Models\Wiki\AnimeSeason;
use App\Models\Wiki\Anime;
use App\Models\Wiki\Anime\AnimeSynonym;
use App\Models\Wiki\Anime\AnimeTheme;
use App\Models\Wiki\Anime\Theme\AnimeThemeEntry;
use App\Models\Wiki\ExternalResource;
@@ -63,11 +62,6 @@ class AnimeFactory extends Factory
{
return $this->afterCreating(
function (Anime $anime): void {
AnimeSynonym::factory()
->for($anime)
->count(fake()->numberBetween(1, 3))
->create();
AnimeTheme::factory()
->for($anime)
->for(Song::factory())
@@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
namespace Database\Factories\Wiki;
use App\Enums\Models\Wiki\SynonymType;
use App\Models\Wiki\Anime;
use App\Models\Wiki\Synonym;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Arr;
/**
* @method Synonym createOne($attributes = [])
* @method Synonym makeOne($attributes = [])
*
* @extends Factory<Synonym>
*/
class SynonymFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var class-string<Synonym>
*/
protected $model = Synonym::class;
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
$type = Arr::random(SynonymType::cases());
return [
Synonym::ATTRIBUTE_TEXT => fake()->words(3, true),
Synonym::ATTRIBUTE_TYPE => $type->value,
];
}
public function forAnime(): static
{
return $this->for(Anime::factory(), Synonym::RELATION_SYNONYMABLE);
}
}
@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
if (! Schema::hasTable('synonyms')) {
Schema::create('synonyms', function (Blueprint $table) {
$table->id('synonym_id');
$table->morphs('synonymable');
$table->string('text');
$table->integer('type');
$table->timestamps(6);
$table->softDeletes(precision: 6);
});
}
}
};
@@ -40,6 +40,7 @@ use App\Models\Wiki\Song;
use App\Models\Wiki\Song\Membership;
use App\Models\Wiki\Song\Performance;
use App\Models\Wiki\Studio;
use App\Models\Wiki\Synonym;
use App\Models\Wiki\Video;
use App\Models\Wiki\Video\VideoScript;
use Illuminate\Database\Seeder;
@@ -100,6 +101,7 @@ class PermissionSeeder extends Seeder
$this->registerResource(Series::class, $extendedCrudPermissions);
$this->registerResource(Song::class, $extendedCrudPermissions);
$this->registerResource(Studio::class, $extendedCrudPermissions);
$this->registerResource(Synonym::class, $extendedCrudPermissions);
$this->registerResource(Video::class, $extendedCrudPermissions);
$this->registerResource(VideoScript::class, $extendedCrudPermissions);
@@ -41,6 +41,7 @@ use App\Models\Wiki\Song;
use App\Models\Wiki\Song\Membership;
use App\Models\Wiki\Song\Performance;
use App\Models\Wiki\Studio;
use App\Models\Wiki\Synonym;
use App\Models\Wiki\Video;
use App\Models\Wiki\Video\VideoScript;
use Illuminate\Support\Arr;
@@ -108,6 +109,7 @@ class AdminSeeder extends RoleSeeder
$this->configureResource($role, Series::class, $extendedCrudPermissions);
$this->configureResource($role, Song::class, $extendedCrudPermissions);
$this->configureResource($role, Studio::class, $extendedCrudPermissions);
$this->configureResource($role, Synonym::class, $extendedCrudPermissions);
$this->configureResource($role, Video::class, $extendedCrudPermissions);
$this->configureResource($role, VideoScript::class, $extendedCrudPermissions);
@@ -32,6 +32,7 @@ use App\Models\Wiki\Song;
use App\Models\Wiki\Song\Membership;
use App\Models\Wiki\Song\Performance;
use App\Models\Wiki\Studio;
use App\Models\Wiki\Synonym;
use App\Models\Wiki\Video;
use App\Models\Wiki\Video\VideoScript;
@@ -91,6 +92,7 @@ class ContentModeratorRoleSeeder extends RoleSeeder
$this->configureResource($role, Series::class, $extendedCrudPermissions);
$this->configureResource($role, Song::class, $extendedCrudPermissions);
$this->configureResource($role, Studio::class, $extendedCrudPermissions);
$this->configureResource($role, Synonym::class, $extendedCrudPermissions);
$this->configureResource($role, Video::class, [CrudPermission::VIEW, CrudPermission::UPDATE]);
$this->configureResource($role, VideoScript::class, [CrudPermission::VIEW]);
@@ -31,6 +31,7 @@ use App\Models\Wiki\Song;
use App\Models\Wiki\Song\Membership;
use App\Models\Wiki\Song\Performance;
use App\Models\Wiki\Studio;
use App\Models\Wiki\Synonym;
use App\Models\Wiki\Video;
use App\Models\Wiki\Video\VideoScript;
@@ -78,6 +79,7 @@ class ContributorRoleSeeder extends RoleSeeder
$this->configureResource($role, Series::class, [CrudPermission::VIEW]);
$this->configureResource($role, Song::class, [CrudPermission::VIEW]);
$this->configureResource($role, Studio::class, [CrudPermission::VIEW]);
$this->configureResource($role, Synonym::class, [CrudPermission::VIEW]);
$this->configureResource($role, Video::class, [CrudPermission::VIEW]);
$this->configureResource($role, VideoScript::class, [CrudPermission::VIEW]);
@@ -31,6 +31,7 @@ use App\Models\Wiki\Song;
use App\Models\Wiki\Song\Membership;
use App\Models\Wiki\Song\Performance;
use App\Models\Wiki\Studio;
use App\Models\Wiki\Synonym;
use App\Models\Wiki\Video;
use App\Models\Wiki\Video\VideoScript;
@@ -78,6 +79,7 @@ class DeveloperRoleSeeder extends RoleSeeder
$this->configureResource($role, Series::class, [CrudPermission::VIEW]);
$this->configureResource($role, Song::class, [CrudPermission::VIEW]);
$this->configureResource($role, Studio::class, [CrudPermission::VIEW]);
$this->configureResource($role, Synonym::class, [CrudPermission::VIEW]);
$this->configureResource($role, Video::class, [CrudPermission::VIEW]);
$this->configureResource($role, VideoScript::class, [CrudPermission::VIEW]);
@@ -32,6 +32,7 @@ use App\Models\Wiki\Song;
use App\Models\Wiki\Song\Membership;
use App\Models\Wiki\Song\Performance;
use App\Models\Wiki\Studio;
use App\Models\Wiki\Synonym;
use App\Models\Wiki\Video;
use App\Models\Wiki\Video\VideoScript;
@@ -91,6 +92,7 @@ class EncoderRoleSeeder extends RoleSeeder
$this->configureResource($role, Series::class, $extendedCrudPermissions);
$this->configureResource($role, Song::class, $extendedCrudPermissions);
$this->configureResource($role, Studio::class, $extendedCrudPermissions);
$this->configureResource($role, Synonym::class, $extendedCrudPermissions);
$this->configureResource($role, Video::class, $extendedCrudPermissions);
$this->configureResource($role, VideoScript::class, $extendedCrudPermissions);
@@ -31,6 +31,7 @@ use App\Models\Wiki\Song;
use App\Models\Wiki\Song\Membership;
use App\Models\Wiki\Song\Performance;
use App\Models\Wiki\Studio;
use App\Models\Wiki\Synonym;
use App\Models\Wiki\Video;
use App\Models\Wiki\Video\VideoScript;
@@ -78,6 +79,7 @@ class PanelViewerRoleSeeder extends RoleSeeder
$this->configureResource($role, Series::class, [CrudPermission::VIEW]);
$this->configureResource($role, Song::class, [CrudPermission::VIEW]);
$this->configureResource($role, Studio::class, [CrudPermission::VIEW]);
$this->configureResource($role, Synonym::class, [CrudPermission::VIEW]);
$this->configureResource($role, Video::class, [CrudPermission::VIEW]);
$this->configureResource($role, VideoScript::class, [CrudPermission::VIEW]);
@@ -31,6 +31,7 @@ use App\Models\Wiki\Song;
use App\Models\Wiki\Song\Membership;
use App\Models\Wiki\Song\Performance;
use App\Models\Wiki\Studio;
use App\Models\Wiki\Synonym;
use App\Models\Wiki\Video;
use App\Models\Wiki\Video\VideoScript;
@@ -78,6 +79,7 @@ class PatronRoleSeeder extends RoleSeeder
$this->configureResource($role, Series::class, [CrudPermission::VIEW]);
$this->configureResource($role, Song::class, [CrudPermission::VIEW]);
$this->configureResource($role, Studio::class, [CrudPermission::VIEW]);
$this->configureResource($role, Synonym::class, [CrudPermission::VIEW]);
$this->configureResource($role, Video::class, [CrudPermission::VIEW]);
$this->configureResource($role, VideoScript::class, [CrudPermission::VIEW]);
@@ -13,6 +13,7 @@ use App\Models\Wiki\Artist;
use App\Models\Wiki\Series;
use App\Models\Wiki\Song;
use App\Models\Wiki\Studio;
use App\Models\Wiki\Synonym;
use App\Models\Wiki\Video;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Seeder;
@@ -51,6 +52,7 @@ class ImportModelsSeeder extends Seeder
$this->scoutImport(Series::class);
$this->scoutImport(Song::class);
$this->scoutImport(Studio::class);
$this->scoutImport(Synonym::class);
$this->scoutImport(Video::class);
}

Some files were not shown because too many files have changed in this diff Show More