feat: add post_comments table, model, and factory
This commit is contained in:
parent
e1965f9f7c
commit
7f491b2c2c
5 changed files with 159 additions and 2 deletions
|
|
@ -4,15 +4,18 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use App\DataTransferObjects\MediaItem;
|
||||
use App\Enums\Post\Status as PostStatus;
|
||||
use Database\Factories\PostFactory;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class Post extends Model
|
||||
{
|
||||
|
|
@ -22,8 +25,9 @@ class Post extends Model
|
|||
protected $fillable = [
|
||||
'workspace_id',
|
||||
'user_id',
|
||||
'content',
|
||||
'media',
|
||||
'status',
|
||||
'synced',
|
||||
'scheduled_at',
|
||||
'published_at',
|
||||
];
|
||||
|
|
@ -32,12 +36,24 @@ protected function casts(): array
|
|||
{
|
||||
return [
|
||||
'status' => PostStatus::class,
|
||||
'synced' => 'boolean',
|
||||
'media' => 'array',
|
||||
'scheduled_at' => 'datetime',
|
||||
'published_at' => 'datetime',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get media items as a collection of MediaItem DTOs.
|
||||
*
|
||||
* @return Collection<int, MediaItem>
|
||||
*/
|
||||
protected function mediaItems(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => collect($this->media ?? [])->map(fn (array $item) => MediaItem::fromArray($item)),
|
||||
);
|
||||
}
|
||||
|
||||
public function workspace(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Workspace::class);
|
||||
|
|
@ -53,6 +69,11 @@ public function postPlatforms(): HasMany
|
|||
return $this->hasMany(PostPlatform::class);
|
||||
}
|
||||
|
||||
public function comments(): HasMany
|
||||
{
|
||||
return $this->hasMany(PostComment::class);
|
||||
}
|
||||
|
||||
public function labels(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(WorkspaceLabel::class);
|
||||
|
|
|
|||
65
app/Models/PostComment.php
Normal file
65
app/Models/PostComment.php
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Database\Factories\PostCommentFactory;
|
||||
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class PostComment extends Model
|
||||
{
|
||||
/** @use HasFactory<PostCommentFactory> */
|
||||
use HasFactory, HasUuids;
|
||||
|
||||
protected $fillable = [
|
||||
'post_id',
|
||||
'user_id',
|
||||
'parent_id',
|
||||
'body',
|
||||
'reactions',
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'reactions' => 'array',
|
||||
];
|
||||
}
|
||||
|
||||
public function post(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Post::class);
|
||||
}
|
||||
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public function parent(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(self::class, 'parent_id');
|
||||
}
|
||||
|
||||
public function replies(): HasMany
|
||||
{
|
||||
return $this->hasMany(self::class, 'parent_id')->oldest();
|
||||
}
|
||||
|
||||
public function addReaction(string $userId, string $emoji): void
|
||||
{
|
||||
$reactions = $this->reactions ?? [];
|
||||
$reactions = array_filter($reactions, fn (array $r) => ! (data_get($r, 'user_id') === $userId && data_get($r, 'emoji') === $emoji));
|
||||
|
||||
if (count($reactions) === count($this->reactions ?? [])) {
|
||||
$reactions[] = ['user_id' => $userId, 'emoji' => $emoji];
|
||||
}
|
||||
|
||||
$this->update(['reactions' => array_values($reactions)]);
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@
|
|||
use App\Models\NotificationPreference;
|
||||
use App\Models\Plan;
|
||||
use App\Models\Post;
|
||||
use App\Models\PostComment;
|
||||
use App\Models\PostPlatform;
|
||||
use App\Models\SocialAccount;
|
||||
use App\Models\Subscription;
|
||||
|
|
@ -95,6 +96,7 @@ protected function configureMorphMap(): void
|
|||
'plan' => Plan::class,
|
||||
'notificationPreference' => NotificationPreference::class,
|
||||
'post' => Post::class,
|
||||
'postComment' => PostComment::class,
|
||||
'postPlatform' => PostPlatform::class,
|
||||
'socialAccount' => SocialAccount::class,
|
||||
'subscription' => Subscription::class,
|
||||
|
|
|
|||
32
database/factories/PostCommentFactory.php
Normal file
32
database/factories/PostCommentFactory.php
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Post;
|
||||
use App\Models\PostComment;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/** @extends Factory<PostComment> */
|
||||
class PostCommentFactory extends Factory
|
||||
{
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'post_id' => Post::factory(),
|
||||
'user_id' => User::factory(),
|
||||
'body' => $this->faker->sentence(),
|
||||
'reactions' => [],
|
||||
];
|
||||
}
|
||||
|
||||
public function reply(PostComment $parent): static
|
||||
{
|
||||
return $this->state(fn () => [
|
||||
'post_id' => $parent->post_id,
|
||||
'parent_id' => $parent->id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?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
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('post_comments', function (Blueprint $table) {
|
||||
$table->uuid('id')->primary();
|
||||
$table->uuid('post_id');
|
||||
$table->uuid('user_id')->nullable();
|
||||
$table->uuid('parent_id')->nullable();
|
||||
$table->text('body');
|
||||
$table->json('reactions')->default('[]');
|
||||
$table->timestamps();
|
||||
|
||||
$table->foreign('post_id')->references('id')->on('posts')->cascadeOnDelete();
|
||||
$table->foreign('user_id')->references('id')->on('users')->nullOnDelete();
|
||||
|
||||
$table->index(['post_id', 'created_at']);
|
||||
});
|
||||
|
||||
Schema::table('post_comments', function (Blueprint $table) {
|
||||
$table->foreign('parent_id')->references('id')->on('post_comments')->cascadeOnDelete();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('post_comments');
|
||||
}
|
||||
};
|
||||
Loading…
Reference in a new issue