-
-
Save habibtalib/c07ab12ec436833bd0d83ad0ccca1e5a to your computer and use it in GitHub Desktop.
Using Filament with Spatie Media Library
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Model Brand.php. | |
<?php | |
namespace App\Models\Admin; | |
use Cviebrock\EloquentSluggable\Sluggable; | |
use Illuminate\Database\Eloquent\Factories\HasFactory; | |
use Illuminate\Database\Eloquent\Model; | |
use Illuminate\Support\Str; | |
use Spatie\MediaLibrary\HasMedia; | |
use Spatie\MediaLibrary\InteractsWithMedia; | |
class Brand extends Model implements HasMedia | |
{ | |
use HasFactory, InteractsWithMedia, Sluggable; | |
protected $fillable = [ | |
'name', | |
'abbrv', | |
]; | |
public function sluggable(): array | |
{ | |
return [ | |
'slug' => [ | |
'source' => 'name', | |
] | |
]; | |
} | |
//With this method i attach a single logo to the model | |
public function attachLogo($path, $fileName = '') : self | |
{ | |
if ($fileName === '') | |
{ | |
$extension = Str::afterLast($path, '.'); | |
$fileName = strtolower(str_replace(['#', '/', '\\', ' '], '-', $this->name)).'_'.$this->id.'.'.$extension; | |
} | |
$this->addMedia($path) | |
->usingFileName($fileName) | |
->usingName($this->name.'_'.$this->id) | |
->toMediaCollection('brands'); | |
return $this; | |
} | |
public function registerMediaCollections(): void | |
{ | |
$this->addMediaCollection('brands') | |
->useDisk('brands') | |
->acceptsMimeTypes([ | |
'image/jpeg', | |
'image/png', | |
'image/svg+xml', | |
'image/webp', | |
'image/gif', | |
'image/svg', | |
]) | |
->singleFile(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//App\Filament\Resources\Admin\BrandResource\BrandResource.php | |
//Here we define the Form and the Record List of the Resource. | |
//The only thing of notice is how the logo is showed in the record list using the callback 'getValueUsing => ' | |
<?php | |
namespace App\Filament\Resources\Admin; | |
use App\Filament\Resources\Admin\BrandResource\Pages; | |
use App\Filament\Resources\Admin\BrandResource\RelationManagers; | |
use App\Filament\Roles; | |
use App\Models\Admin\Brand; | |
use Filament\Resources\Forms\Components; | |
use Filament\Resources\Forms\Form; | |
use Filament\Resources\Resource; | |
use Filament\Resources\Tables\Columns; | |
use Filament\Resources\Tables\Filter; | |
use Filament\Resources\Tables\Table; | |
class BrandResource extends Resource | |
{ | |
public static $icon = 'heroicon-o-collection'; | |
public static $model = Brand::class; | |
public static $label = 'Marcas'; | |
public static $navigationSort = 1; | |
public static function form(Form $form) | |
{ | |
return $form->schema([ | |
Components\TextInput::make('name') | |
->autofocus() | |
->rules(['required', 'max:100']) | |
->maxLength(100) | |
->placeholder('Nombre') | |
->label('Nombre'), | |
Components\TextInput::make('abbrv') | |
->rules(['required', 'max:6']) | |
->maxLength(6) | |
->placeholder('Ingresa una abreviatura para la marca. La abreviatura se usará para generar el SKU de los productos') | |
->label('Abreviatura') | |
->hint('Máximo 6 caracteres'), | |
Components\FileUpload::make('logo') | |
->image() | |
->label('Logo'), | |
]); | |
} | |
public static function table(Table $table) | |
{ | |
return $table->columns([ | |
Columns\Text::make('name') | |
->primary() | |
->label('Nombre') | |
->searchable() | |
->sortable(), | |
Columns\Text::make('abbrv') | |
->label('Abbrv'), | |
Columns\Image::make('logo') | |
->label('Logo') | |
->size(80) | |
->getValueUsing(function($record) { | |
return $record->getFirstMediaUrl('brands'); | |
}), | |
])->filters([ | |
// | |
]); | |
} | |
public static function relations() | |
{ | |
return [ | |
// | |
]; | |
} | |
public static function routes() | |
{ | |
return [ | |
Pages\ListBrands::routeTo('/', 'index'), | |
Pages\CreateBrand::routeTo('/create', 'create'), | |
Pages\EditBrand::routeTo('/{record}/edit', 'edit'), | |
]; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//App\Filament\Resources\Admin\BrandResource\Pages\CreateBrand.php | |
<?php | |
namespace App\Filament\Resources\Admin\BrandResource\Pages; | |
use App\Filament\Resources\Admin\BrandResource; | |
use Filament\Forms\Components\FileUpload; | |
use Filament\Resources\Pages\CreateRecord; | |
class CreateBrand extends CreateRecord | |
{ | |
public static $resource = BrandResource::class; | |
public static $showRoute = 'edit'; | |
//This method gives me the real path of the temporary file that Livewire uploaded to the server. I need this path so i can | |
//attach the media with my model using Spatie Media Library. | |
public function getLogoRealPath() | |
{ | |
$temporaryUploadedFile = $this->getTemporaryUploadedFile('record.logo'); //Upload File Field named 'logo' | |
if ($temporaryUploadedFile) | |
return $temporaryUploadedFile->getRealPath(); | |
return ''; | |
} | |
//Overriding the create method of the CreateRecord class | |
//I had to do this because how the method handles the uploaded file doesn't allowed me to use any hook to intercept the deleting | |
//of the temporary file. Once the model is created, the temporary file is long time gone, so i don't have how to attach the media | |
//to my model with the spatie media library. | |
//All the other methods and hooks are called as the original class in the same order. Only is removed the method that deletes the | |
//temporary file and it is added the code to attach the media to the model. | |
public function create($another = false) | |
{ | |
$this->callHook('beforeValidate'); | |
$this->validateTemporaryUploadedFiles(); | |
$this->validate(); | |
$this->callHook('afterValidate'); | |
$this->callHook('beforeCreate'); | |
$record = static::getModel()::create($this->record); | |
$logoPath = $this->getLogoRealPath(); | |
if ($logoPath !== '') | |
$record->attachLogo($logoPath); | |
$this->callHook('afterCreate'); | |
if ($another) | |
{ | |
$this->fillRecord(); | |
$this->notify(__(static::$createdMessage)); | |
return; | |
} | |
$this->redirect($this->getResource()::generateUrl(static::$showRoute, [ | |
'record' => $record, | |
])); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//App\Filament\Resources\Admin\BrandResource\Pages\EditBrand.php | |
<?php | |
namespace App\Filament\Resources\Admin\BrandResource\Pages; | |
use App\Filament\Resources\Admin\BrandResource; | |
use Filament\Forms\Components\FileUpload; | |
use Filament\Resources\Pages\EditRecord; | |
use Illuminate\Support\Facades\DB; | |
class EditBrand extends EditRecord | |
{ | |
public static $resource = BrandResource::class; | |
public function getLogoRealPath() | |
{ | |
$temporaryUploadedFile = $this->getTemporaryUploadedFile('record.logo'); | |
if ($temporaryUploadedFile) | |
return $temporaryUploadedFile->getRealPath(); | |
return ''; | |
} | |
//In the edit feature, the method to override is the save of the EditRecord class. Basically the steps are the same as in create | |
//record. | |
//Only thing to note, if i tried to use $record->save or $record->update, i didn't find why, it tried to save the 'logo' field in | |
//the brands table, which obvioulsy don't exist and throwed me an exception. That's why the model's save i handled it with the | |
//DB facade. | |
public function save() | |
{ | |
$this->callHook('beforeValidate'); | |
$this->validateTemporaryUploadedFiles(); | |
$data = $this->validate(); | |
$this->callHook('afterValidate'); | |
$this->callHook('beforeSave'); | |
$affectedRows = DB::table('brands') | |
->where('id', $this->record->id) | |
->update([ | |
'name' => $data['record']['name'], | |
'abbrv' => $data['record']['abbrv'], | |
]); | |
$logoPath = $this->getLogoRealPath(); | |
if ($logoPath !== '') | |
$this->record->attachLogo($logoPath); | |
$this->callHook('afterSave'); | |
$this->notify(__(static::$savedMessage)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment