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\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use Spatie\MediaLibrary\HasMedia;
|
use Spatie\MediaLibrary\HasMedia;
|
||||||
@ -35,4 +36,9 @@ public function journalists(): HasMany
|
|||||||
{
|
{
|
||||||
return $this->hasMany(Journalist::class);
|
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\Attributes\Scope;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
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
|
public function company(): HasOne
|
||||||
{
|
{
|
||||||
return $this->hasOne(Company::class);
|
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