25
Jul '18
I know I know. Rely too much on traits and you’re asking for trouble. But when used correctly, for self-contained bolt-on functionality they really can be fantastic and save loads of time.
There only condition for this logic is that any record with which you are using this must have a ‘logo’ field. Yeah I know I could have done a more advanced version with a separate logo table and a polymorphic relationship, but it’s not like a standard system will have 2 dozen records that all require logos against them so I’ve kept it simple.
I’ve used the word ‘logo’ here, but it’s a generic image storing trait and could be used for anything. You’ll also notice an optional config option of ‘app.directory.logo’, which, if provided, will be used as a relative path below the application’s public folder, otherwise ‘/logos’ will be used.
This assumes that you have an image referenced as ‘logo_file’ in your request and have triggered a save on the parent record.
namespace App\Trt; trait Logo { /** * Custom boot method */ public static function bootLogo() { /* * Trigger on save */ static::saved(function ($record) { try { if(request()->hasFile('logo_file') && request()->file('logo_file')->isValid()) { $logo_file = request()->file('logo_file'); $logo_folder = public_path(config('app.directory.logo', '/logos')); if(is_dir($logo_folder) && is_writable($logo_folder)) { //Prepending the record ID to ensure uniqueness //Could also prepend parent record type / sanitised model name if it's to be used for multiple records $file_name = $record->id . '_' . $logo_file->getClientOriginalName(); $record->clearLogo(false); if($logo_file->move($logo_folder, $file_name)) { $record->logo = $file_name; //Direct update here so we don't trigger any callbacks \DB::table($record->getTable())->where('id', $record->id)->update(['logo' => $file_name]); } } else { \Log::error('Logo folder is not writable ' . $logo_folder); } } elseif(request()->clear_logo) { $record->clearLogo(); } } catch(\Exception $e) { } }); /* * Trigger on delete */ static::deleting(function ($record) { $record->clearLogo(false); }); } /** * Check for logo * @return boolean */ public function hasLogo() { return ($this->logo && is_file($this->logoPath())); } /** * Logo URL * @return string|false */ public function logoURL() { return $this->logo ? url(config('app.directory.logo', '/logos') . '/' . $this->logo) : false; } /** * Logo Path * @return string|false */ public function logoPath() { return $this->logo ? public_path(config('app.directory.logo', '/logos') . '/' . $this->logo) : false; } /** * Clear Logo * @param boolean [$save=true] Save * @return boolean */ public function clearLogo($save = true) { if($this->logo) { if($this->hasLogo()) unlink($this->logoPath()); $this->logo = null; if($save) $this->save(); return true; } return false; } }
And that’s it!