feat(models): add relationships to PartnerMedia and User models
- Introduced a many-to-many relationship in PartnerMedia for announcements. - Added a has-many relationship in User for news authored by the user. - Implemented an active scope in User for filtering active users.
This commit is contained in:
parent
2c5b057958
commit
8386ea0d93
@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Publication\Announcements;
|
||||
|
||||
use App\Filament\Actions\DefaultBulkActions;
|
||||
use App\Filament\Columns\TimestampColumns;
|
||||
use App\Filament\Resources\Publication\Announcements\Pages\ManageAnnouncements;
|
||||
use App\Models\Announcement;
|
||||
use App\Models\PartnerMedia;
|
||||
use BackedEnum;
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Actions\ForceDeleteAction;
|
||||
use Filament\Actions\RestoreAction;
|
||||
use Filament\Forms\Components\CheckboxList;
|
||||
use Filament\Forms\Components\Textarea;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\TrashedFilter;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\SoftDeletingScope;
|
||||
use UnitEnum;
|
||||
|
||||
class AnnouncementResource extends Resource
|
||||
{
|
||||
protected static ?string $model = Announcement::class;
|
||||
|
||||
protected static string|BackedEnum|null $navigationIcon = Heroicon::Megaphone;
|
||||
|
||||
protected static ?string $navigationLabel = 'Pengumuman';
|
||||
|
||||
protected static string|UnitEnum|null $navigationGroup = 'Publikasi';
|
||||
|
||||
protected static ?string $slug = 'publication/announcements';
|
||||
|
||||
protected static ?string $recordTitleAttribute = 'content';
|
||||
|
||||
protected static ?int $navigationSort = 2;
|
||||
|
||||
public static function form(Schema $schema): Schema
|
||||
{
|
||||
return $schema
|
||||
->components([
|
||||
Textarea::make('content')
|
||||
->label('Konten')
|
||||
->placeholder('Diberitahukan kepada seluruh media untuk update dokumen...')
|
||||
->autocomplete(false)
|
||||
->autofocus()
|
||||
->required()
|
||||
->rows(4)
|
||||
->columnSpanFull(),
|
||||
|
||||
CheckboxList::make('partnerMedia')
|
||||
->label('Kirim Kepada')
|
||||
->required()
|
||||
->relationship('partnerMedia', 'name')
|
||||
->options(function () {
|
||||
return PartnerMedia::query()->pluck('name', 'id');
|
||||
})
|
||||
->searchable()
|
||||
->noSearchResultsMessage('Tidak ada media yang ditemukan.')
|
||||
->helperText('Pilih media yang akan menerima pengumuman ini')
|
||||
->columnSpanFull(),
|
||||
])
|
||||
->columns(1);
|
||||
}
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->recordTitleAttribute('content')
|
||||
->columns([
|
||||
TextColumn::make('content')
|
||||
->label('Konten')
|
||||
->searchable()
|
||||
->sortable()
|
||||
->wrap()
|
||||
->limit(100),
|
||||
|
||||
TextColumn::make('partnerMedia.name')
|
||||
->label('Penerima')
|
||||
->listWithLineBreaks()
|
||||
->limitList(3)
|
||||
->expandableLimitedList()
|
||||
->placeholder('Tidak ada penerima'),
|
||||
|
||||
...TimestampColumns::make(),
|
||||
])
|
||||
->filters([
|
||||
TrashedFilter::make()->native(false),
|
||||
])
|
||||
->recordActions([
|
||||
EditAction::make()->modalWidth('lg'),
|
||||
DeleteAction::make(),
|
||||
ForceDeleteAction::make(),
|
||||
RestoreAction::make(),
|
||||
])
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
...DefaultBulkActions::make('Pengumuman'),
|
||||
]),
|
||||
])
|
||||
->emptyStateIcon('heroicon-o-megaphone')
|
||||
->emptyStateDescription('Setelah Anda membuat data pertama, maka akan muncul disini.')
|
||||
->defaultSort('created_at', 'desc')
|
||||
->deferFilters(false);
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => ManageAnnouncements::route('/'),
|
||||
];
|
||||
}
|
||||
|
||||
public static function getRecordRouteBindingEloquentQuery(): Builder
|
||||
{
|
||||
return parent::getRecordRouteBindingEloquentQuery()
|
||||
->withoutGlobalScopes([
|
||||
SoftDeletingScope::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Publication\Announcements\Pages;
|
||||
|
||||
use App\Filament\Resources\Publication\Announcements\AnnouncementResource;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Resources\Pages\ManageRecords;
|
||||
|
||||
class ManageAnnouncements extends ManageRecords
|
||||
{
|
||||
protected static ?string $title = 'Pengumuman';
|
||||
|
||||
protected static string $resource = AnnouncementResource::class;
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
CreateAction::make()
|
||||
->label('Tambah')
|
||||
->modalHeading('Tambah Pengumuman')
|
||||
->modalSubmitActionLabel('Simpan')
|
||||
->modalCancelActionLabel('Batal')
|
||||
->extraModalFooterActions(fn (CreateAction $action): array => [
|
||||
$action->makeModalSubmitAction('createAnother', arguments: ['another' => true])
|
||||
->label('Simpan dan Tambah Lagi'),
|
||||
])
|
||||
->modalWidth('lg'),
|
||||
];
|
||||
}
|
||||
}
|
||||
20
app/Models/Announcement.php
Normal file
20
app/Models/Announcement.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Announcement extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
protected $guarded = ['id'];
|
||||
|
||||
public function partnerMedia(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(PartnerMedia::class, 'announcement_media');
|
||||
}
|
||||
}
|
||||
25
app/Models/AnnouncementMedia.php
Normal file
25
app/Models/AnnouncementMedia.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class AnnouncementUser extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
protected $guarded = ['id'];
|
||||
|
||||
public function announcement(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Announcement::class);
|
||||
}
|
||||
|
||||
public function partnerMedia(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(PartnerMedia::class);
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,7 @@
|
||||
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\Database\Eloquent\SoftDeletes;
|
||||
use Spatie\MediaLibrary\HasMedia;
|
||||
@ -35,4 +36,9 @@ public function journalists(): HasMany
|
||||
{
|
||||
return $this->hasMany(Journalist::class);
|
||||
}
|
||||
|
||||
public function announcements(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Announcement::class, 'announcement_media');
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
use Illuminate\Database\Eloquent\Attributes\Scope;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
@ -44,8 +45,19 @@ protected function withoutDeveloper(Builder $query): void
|
||||
});
|
||||
}
|
||||
|
||||
#[Scope]
|
||||
protected function active(Builder $query): void
|
||||
{
|
||||
$query->where('is_active', IsActive::ACTIVE);
|
||||
}
|
||||
|
||||
public function company(): HasOne
|
||||
{
|
||||
return $this->hasOne(Company::class);
|
||||
}
|
||||
|
||||
public function news(): HasMany
|
||||
{
|
||||
return $this->hasMany(News::class, 'author_id');
|
||||
}
|
||||
}
|
||||
|
||||
46
database/factories/AnnouncementFactory.php
Normal file
46
database/factories/AnnouncementFactory.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Announcement;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Announcement>
|
||||
*/
|
||||
class AnnouncementFactory extends Factory
|
||||
{
|
||||
protected $model = Announcement::class;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'content' => $this->faker->paragraphs(2, true),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the announcement is important.
|
||||
*/
|
||||
public function important(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'content' => 'PENTING: '.$this->faker->sentence(10),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the announcement is informational.
|
||||
*/
|
||||
public function informational(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'content' => 'INFORMASI: '.$this->faker->paragraph(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
49
database/factories/AnnouncementUserFactory.php
Normal file
49
database/factories/AnnouncementUserFactory.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Announcement;
|
||||
use App\Models\AnnouncementUser;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\AnnouncementUser>
|
||||
*/
|
||||
class AnnouncementUserFactory extends Factory
|
||||
{
|
||||
protected $model = AnnouncementUser::class;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'announcement_id' => Announcement::factory(),
|
||||
'partner_media_id' => PartnerMedia::factory(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the announcement user is for a specific announcement.
|
||||
*/
|
||||
public function forAnnouncement(Announcement $announcement): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'announcement_id' => $announcement->id,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the announcement user is for a specific partner media.
|
||||
*/
|
||||
public function forPartnerMedia(PartnerMedia $partnerMedia): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'partner_media_id' => $partnerMedia->id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
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
|
||||
{
|
||||
Schema::create('announcements', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->text('content');
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
$table->timestamp('updated_at')->nullable()->useCurrentOnUpdate();
|
||||
$table->softDeletes();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('announcements');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Announcement;
|
||||
use App\Models\PartnerMedia;
|
||||
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
|
||||
{
|
||||
Schema::create('announcement_media', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignIdFor(Announcement::class);
|
||||
$table->foreignIdFor(PartnerMedia::class);
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
$table->timestamp('updated_at')->nullable()->useCurrentOnUpdate();
|
||||
$table->softDeletes();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('announcement_media');
|
||||
}
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user