diff --git a/src/SettingsServiceProvider.php b/src/SettingsServiceProvider.php index 8374da4..6a7d9df 100644 --- a/src/SettingsServiceProvider.php +++ b/src/SettingsServiceProvider.php @@ -51,6 +51,14 @@ public function boot() // publish translation files $this->publishes([__DIR__.'/resources/lang' => resource_path('lang/vendor/backpack')], 'lang'); + + // use the vendor configuration file as fallback + $this->mergeConfigFrom( + __DIR__.'/config/backpack/settings.php', + 'backpack.settings' + ); + // publish config file + $this->publishes([__DIR__.'/config' => config_path()], 'config'); } /** diff --git a/src/app/Http/Controllers/SettingCrudController.php b/src/app/Http/Controllers/SettingCrudController.php index 245578b..52aaa1f 100644 --- a/src/app/Http/Controllers/SettingCrudController.php +++ b/src/app/Http/Controllers/SettingCrudController.php @@ -9,34 +9,67 @@ class SettingCrudController extends CrudController { - public function __construct() + public function setup() { - parent::__construct(); - $this->crud->setModel("Backpack\Settings\app\Models\Setting"); $this->crud->setEntityNameStrings(trans('backpack::settings.setting_singular'), trans('backpack::settings.setting_plural')); $this->crud->setRoute(config('backpack.base.route_prefix', 'admin').'/setting'); - $this->crud->denyAccess(['create', 'delete']); $this->crud->setColumns([ [ 'name' => 'name', 'label' => trans('backpack::settings.name'), ], [ - 'name' => 'value', - 'label' => trans('backpack::settings.value'), + 'name' => 'key', + 'label' => trans('backpack::settings.key'), + ], + [ + 'name' => 'value', + 'label' => trans('backpack::settings.value'), + 'type' => 'model_function', + 'function_name' => 'getValueFunction', ], [ 'name' => 'description', 'label' => trans('backpack::settings.description'), ], ]); - $this->crud->addField([ - 'name' => 'name', - 'label' => trans('backpack::settings.name'), - 'type' => 'text', - 'attributes' => [ - 'disabled' => 'disabled', + $this->crud->addFields([ + [ + 'name' => 'name', + 'label' => trans('backpack::settings.name'), + 'type' => 'text', + ], + [ + 'name' => 'key', + 'label' => trans('backpack::settings.key'), + 'type' => 'text', + ], + [ + 'name' => 'description', + 'label' => trans('backpack::settings.description'), + 'type' => 'text', + ], + [ // select_from_array + 'name' => 'field', + 'label' => trans('backpack::settings.select_field'), + 'type' => 'select2_from_array', + 'options' => [ + 'text' => 'Text', + 'email' => 'Email', + 'checkbox' => 'Checkbox', + 'number' => 'Number', + 'url' => 'URL', + 'image' => 'Image', + 'password' => 'Password', + 'icon_picker' => 'Icon Picker', + ], + 'allows_null' => false, + ], + [ + 'name' => 'active', + 'label' => trans('backpack::settings.active'), + 'type' => 'checkbox', ], ]); } @@ -55,6 +88,13 @@ public function index() return parent::index(); } + /** + * Store a newly created resource in the database. + * + * @param StoreRequest $request - type injection used for validation using Requests + * + * @return \Illuminate\Http\RedirectResponse + */ public function store(StoreRequest $request) { return parent::storeCrud(); @@ -72,7 +112,7 @@ public function edit($id) $this->crud->hasAccessOrFail('update'); $this->data['entry'] = $this->crud->getEntry($id); - $this->crud->addField((array) json_decode($this->data['entry']->field)); // <---- this is where it's different + $this->crud->addField((array) $this->getFieldJsonValue($id, $this->isImageField($id))); // <---- this is where it's different $this->data['crud'] = $this->crud; $this->data['saveAction'] = $this->getSaveAction(); $this->data['fields'] = $this->crud->getUpdateFields($id); @@ -84,8 +124,72 @@ public function edit($id) return view($this->crud->getEditView(), $this->data); } + /** + * Update the specified resource in the database. + * + * @param UpdateRequest $request - type injection used for validation using Requests + * + * @return \Illuminate\Http\RedirectResponse + */ public function update(UpdateRequest $request) { return parent::updateCrud(); } + + /** + * get the correct field json value to add the correct field to edit form. + * + * @param int $id + * @param bool $isImage + * + * @return array + */ + protected function getFieldJsonValue($id, $isImage = true) + { + $fieldValue = $this->crud->getEntry($id)->field; + + $fieldJson = []; + + if ($isImage == false) { + $fieldJson['name'] = 'value'; + $fieldJson['label'] = 'Value'; + $fieldJson['type'] = $fieldValue; + + return $fieldJson; + } else { + $fieldJson['name'] = 'value'; + $fieldJson['label'] = 'Value'; + $fieldJson['type'] = $fieldValue; + $fieldJson['upload'] = config('backpack.settings.image_upload_enabled'); + $fieldJson['crop'] = config('backpack.settings.image_crop_enabled'); + $fieldJson['aspect_ratio'] = config('backpack.settings.image_aspect_ratio'); + $fieldJson['prefix'] = config('backpack.settings.image_prefix'); + + return $fieldJson; + } + } + + /** + * get the correct field type. + * + * @param int $id + * + * @return string + */ + protected function getFieldType($id) + { + return $this->crud->getEntry($id)->field; + } + + /** + * get the correct field type. + * + * @param int $id + * + * @return bool + */ + protected function isImageField($id) + { + return $this->getFieldType($id) == 'image' ? true : false; + } } diff --git a/src/app/Models/Setting.php b/src/app/Models/Setting.php index 01976f9..c8b12e8 100644 --- a/src/app/Models/Setting.php +++ b/src/app/Models/Setting.php @@ -4,11 +4,197 @@ use Backpack\CRUD\CrudTrait; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Storage; +use Intervention\Image\Facades\Image; +use Prologue\Alerts\Facades\Alert; +/** + * Class Setting. + */ class Setting extends Model { use CrudTrait; protected $table = 'settings'; - protected $fillable = ['value']; + protected $fillable = ['name', 'key', 'value', 'field', 'description', 'active']; + + /** + * Model Boot function + * Need it to delete image file from disk if the field type == image. + */ + public static function boot() + { + parent::boot(); + static::deleting(function ($obj) { + // 1. get field type + $type = $obj->field; + // 2. check if it's image + if ($type == 'image') { + // 3. delete from disk + if (!Storage::disk(config('backpack.settings.images_disk_name'))->delete($obj->value)) { + // filed to delete image file + Alert::error(trans('backpack::settings.delete_image_file_not_message'))->flash(); + } + } + }); + } + + /** + * set field json to database. + * + * @param $field + */ + public function setFieldAttribute($field) + { + $fieldJson = []; + $fieldJson['name'] = 'value'; + $fieldJson['label'] = 'Value'; + $fieldJson['type'] = $field; + + $this->attributes['field'] = json_encode($fieldJson); + } + + /** + * get the correct type value for select2_from_array. + * + * @param $field + * + * @return string + */ + public function getFieldAttribute($field) + { + $fieldDecoded = json_decode($field, true); + + return $fieldDecoded['type']; + } + + /** + * set the correct value and check if image field. + * + * @param $value + */ + public function setValueAttribute($value) + { + // get item id + $id = $this->id; + // get setting object from database + $setting = DB::table($this->table)->where('id', $id)->first(); + // decode field object + $fieldDecoded = json_decode($setting->field, true); + // get field type + $type = $fieldDecoded['type']; + + // column attribute name + $attribute_name = 'value'; + // get images disk + $disk = config('backpack.settings.images_disk_name'); + // get destination folder + $destination_path = config('backpack.settings.images_folder'); + + switch ($type) { + case 'image': + // if the image was erased + if (is_null($value)) { + // delete the image from disk + if (Storage::disk($disk)->delete($this->{$attribute_name})) { + // set null in the database after the successful delete + $this->attributes[$attribute_name] = null; + } + } + + // if a base64 was sent, store it in the db + if (starts_with($value, 'data:image')) { + // 0. Get image extension + preg_match("/^data:image\/(.*);base64/i", $value, $match); + $extension = $match[1]; + // 1. Make the image + $image = Image::make($value); + if (!is_null($image)) { + // 2. Generate a filename. + $filename = md5($value.time()).'.'.$extension; + + try { + // 3. Store the image on disk. + Storage::disk($disk)->put($destination_path.'/'.$filename, $image->stream()); + // 4. Save the path to the database + $this->attributes[$attribute_name] = $destination_path.'/'.$filename; + } catch (\InvalidArgumentException $argumentException) { + // 3. failed to save file + Alert::error($argumentException->getMessage())->flash(); + // 4. set as null when fail to save the image to disk + $this->attributes[$attribute_name] = null; + } + } + } + break; + default: + $this->attributes[$attribute_name] = $value; + break; + } + } + + /** + * get the correct value and check fields types + * and return the correct tags. + * + * @return mixed + */ + public function getValueFunction() + { + $attribute_name = 'value'; + + // get item id + $id = $this->id; + // get setting object from database + $setting = DB::table($this->table)->where('id', $id)->first(); + // decode field object + $fieldDecoded = json_decode($setting->field, true); + // get field type + $type = $fieldDecoded['type']; + // check value set + if (!isset($setting->{$attribute_name})) { + return false; + } + // get value + $value = $setting->{$attribute_name}; + + switch ($type) { + case 'text': + return str_limit(strip_tags($value), 80, '[...]'); + break; + case 'url': + return ''.$value.''; + break; + case 'email': + return ''.$value.''; + break; + case 'checkbox': + if ($value == 1) { + // if true return success label with YES string + $html = 'YES'; + } else { + // if false return danger label with NO string + $html = 'NO'; + } + + return $html; + break; + case 'image': + return 'User Avatar'; + break; + case 'password': + return ''; + break; + case 'number': + return $value; + break; + case 'icon_picker': + return ''; + break; + default: + return $type; + break; + } + } } diff --git a/src/config/backpack/settings.php b/src/config/backpack/settings.php new file mode 100644 index 0000000..f410401 --- /dev/null +++ b/src/config/backpack/settings.php @@ -0,0 +1,15 @@ + 'uploads', // disk where images will be saved + 'images_folder' => 'images', // folder where images will be saved inside it in the specified disk + 'image_upload_enabled' => true, // set to true to allow uploading, false to disable + 'image_crop_enabled' => true, // set to true to allow cropping, false to disable + 'image_aspect_ratio' => 1, // ommit or set to 0 to allow any aspect ratio + 'image_prefix' => 'uploads/', // in case you only store the filename in the database, this text will be prepended to the database value + +]; diff --git a/src/database/migrations/2015_08_04_131614_create_settings_table.php b/src/database/migrations/2015_08_04_131614_create_settings_table.php index 559417d..f7da299 100644 --- a/src/database/migrations/2015_08_04_131614_create_settings_table.php +++ b/src/database/migrations/2015_08_04_131614_create_settings_table.php @@ -19,7 +19,7 @@ public function up() $table->string('description')->nullable(); $table->text('value')->nullable(); $table->text('field'); - $table->tinyInteger('active'); + $table->tinyInteger('active')->default(1); $table->timestamps(); }); } diff --git a/src/resources/lang/en/settings.php b/src/resources/lang/en/settings.php index 1bb425c..7c81279 100644 --- a/src/resources/lang/en/settings.php +++ b/src/resources/lang/en/settings.php @@ -9,10 +9,14 @@ | The following language lines are used for Laravel Backpack - Settings | */ - 'name' => 'Name', - 'value' => 'Value', - 'description' => 'Description', - 'setting_singular' => 'setting', - 'setting_plural' => 'settings', + 'name' => 'Name', + 'value' => 'Value', + 'key' => 'Key', + 'select_field' => 'Select field type', + 'active' => 'is Active', + 'description' => 'Description', + 'setting_singular' => 'setting', + 'setting_plural' => 'settings', + 'delete_image_file_not_message' => "There's been an error. Your image might not have been deleted from the disk.", ];