fix: persist morph map alias on AI-generated Media rows
Both PostAiCreateController::createMediaItem and
PostTemplateController::createMediaItem were doing:
$media = new Media([...]);
$media->mediable_type = Workspace::class; // ← FQCN literal
$media->mediable_id = $workspace->id;
$media->save();
Assigning Workspace::class directly bypasses the morphMap configured in
AppServiceProvider, so rows ended up with mediable_type =
'App\\Models\\Workspace' instead of the alias 'workspace'. Other queries
that pivot through the morphMap (e.g. $workspace->media) lose those
records on hosts where the FQCN doesn't match the alias.
Switch both to the relationship form:
$media = $workspace->media()->create([...]);
Laravel fills mediable_type via the morphMap, producing 'workspace'.
This is the same pattern AssetController and the HasMedia trait already
use; these two AI controllers were the only outliers (`grep -rn
'mediable_type =' app/` confirms).
Added tests/Unit/MediaPolymorphTest as a regression — asserts the
created row's mediable_type is the alias and that the relationship
resolves back to the workspace.
This commit is contained in:
parent
563f752866
commit
6ae48f014f
3 changed files with 38 additions and 12 deletions
|
|
@ -9,7 +9,6 @@
|
|||
use App\Enums\PostPlatform\ContentType;
|
||||
use App\Http\Requests\App\Ai\StartPostCreationRequest;
|
||||
use App\Jobs\Ai\StreamPostCreation;
|
||||
use App\Models\Media;
|
||||
use App\Models\SocialAccount;
|
||||
use App\Models\Workspace;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
|
@ -198,7 +197,9 @@ private function buildMediaArray(Workspace $workspace, array $state): array
|
|||
*/
|
||||
private function createMediaItem(Workspace $workspace, string $path, array $meta = []): array
|
||||
{
|
||||
$media = new Media([
|
||||
// Use the relationship (not `mediable_type = Workspace::class`) so
|
||||
// the morph map alias `'workspace'` is persisted instead of the FQCN.
|
||||
$media = $workspace->media()->create([
|
||||
'collection' => 'ai-generated',
|
||||
'type' => MediaType::Image,
|
||||
'path' => $path,
|
||||
|
|
@ -208,10 +209,6 @@ private function createMediaItem(Workspace $workspace, string $path, array $meta
|
|||
'order' => 0,
|
||||
]);
|
||||
|
||||
$media->mediable_type = Workspace::class;
|
||||
$media->mediable_id = $workspace->id;
|
||||
$media->save();
|
||||
|
||||
return [
|
||||
'id' => $media->id,
|
||||
'path' => $media->path,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
use App\Actions\Post\CreatePost;
|
||||
use App\Enums\Media\Type as MediaType;
|
||||
use App\Http\Resources\App\PostTemplateResource;
|
||||
use App\Models\Media;
|
||||
use App\Models\SocialAccount;
|
||||
use App\Models\Workspace;
|
||||
use App\Services\Image\TemplateImageGenerator;
|
||||
|
|
@ -122,7 +121,9 @@ private function interpolate(string $text, Workspace $workspace): string
|
|||
*/
|
||||
private function createMediaItem(Workspace $workspace, string $path): array
|
||||
{
|
||||
$media = new Media([
|
||||
// Use the relationship (not `mediable_type = Workspace::class`) so
|
||||
// the morph map alias `'workspace'` is persisted instead of the FQCN.
|
||||
$media = $workspace->media()->create([
|
||||
'collection' => 'ai-generated',
|
||||
'type' => MediaType::Image,
|
||||
'path' => $path,
|
||||
|
|
@ -132,10 +133,6 @@ private function createMediaItem(Workspace $workspace, string $path): array
|
|||
'order' => 0,
|
||||
]);
|
||||
|
||||
$media->mediable_type = Workspace::class;
|
||||
$media->mediable_id = $workspace->id;
|
||||
$media->save();
|
||||
|
||||
return [
|
||||
'id' => $media->id,
|
||||
'path' => $media->path,
|
||||
|
|
|
|||
32
tests/Unit/MediaPolymorphTest.php
Normal file
32
tests/Unit/MediaPolymorphTest.php
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Models\Workspace;
|
||||
|
||||
/**
|
||||
* Regression test for a bug where Media rows ended up with
|
||||
* `mediable_type = "App\Models\Workspace"` (FQCN) instead of the
|
||||
* morphMap alias `"workspace"`. The bug source was code that did
|
||||
* `$media->mediable_type = Workspace::class;`
|
||||
* which bypasses the morph map. Using the relationship
|
||||
* (`$workspace->media()->create([...])` or
|
||||
* `$media->mediable()->associate($workspace)`) is the correct path.
|
||||
*/
|
||||
test('Workspace::media()->create persists the morphMap alias, not the FQCN', function () {
|
||||
$workspace = Workspace::factory()->create();
|
||||
|
||||
$media = $workspace->media()->create([
|
||||
'collection' => 'ai-generated',
|
||||
'type' => 'image',
|
||||
'path' => 'test/dummy.webp',
|
||||
'original_filename' => 'dummy.webp',
|
||||
'mime_type' => 'image/webp',
|
||||
'size' => 100,
|
||||
'order' => 0,
|
||||
]);
|
||||
|
||||
expect($media->mediable_type)->toBe('workspace');
|
||||
expect($media->mediable_type)->not->toBe(Workspace::class);
|
||||
expect($media->mediable->is($workspace))->toBeTrue();
|
||||
});
|
||||
Loading…
Reference in a new issue