Laravel – Set global variable from settings table – Here in this article, we will share some of the most common and frequently asked about PHP problem in programming with detailed answers and code samples. There’s nothing quite so frustrating as being faced with PHP errors and being unable to figure out what is preventing your website from functioning as it should like php and laravel . If you have an existing PHP-based website or application that is experiencing performance issues, let’s get thinking about Laravel – Set global variable from settings table.
I’m trying to store all my settings from my settings
table into a global variable, but I’m stucked now(I have no idea what’s the next step), this is my actual model and seeder:
model – Settings.php
class Setting extends Model
{
protected $table = 'settings';
public $timestamps = false;
protected $fillable = [
'name',
'value',
];
}
seeder – SettingsTableSeeder.php
class SettingsTableSeeder extends Seeder
{
public function run()
{
$settings = [
['name' => 'title', 'value' => ''],
['name' => 'facebook', 'value' => ''],
['name' => 'twitter', 'value' => ''],
['name' => 'instagram', 'value' => '']
];
foreach($settings as $setting){
AppSetting::create($setting);
}
}
}
How can I store all the data inside the settings table and make then acessible from blade, or any controller or view?
Edit
Now, my question is, how can i update a single or multiple value(s) from a form?
I have set this up:
My route:
Route::put('/', ['as' => 'setting.update', 'uses' => 'AdminAdminConfiguracoesController@update']);
My AdminAdminConfiguracoesController:
class AdminConfiguracoesController extends AdminBaseController
{
private $repository;
public function __construct(SettingRepository $repository){
$this->repository = $repository;
}
public function geral()
{
return view('admin.pages.admin.configuracoes.geral.index');
}
public function social()
{
return view('admin.pages.admin.configuracoes.social.index');
}
public function analytics()
{
return view('admin.pages.admin.configuracoes.analytics.index');
}
public function update($id, Factory $cache, Setting $setting)
{
$this->repository->findByName($setting);
$cache->forget('settings');
return redirect('admin');
}
}
My SettingRepository:
class SettingRepository
{
private $model;
public function __construct(Setting $model)
{
$this->model = $model;
}
public function findByName($name){
return $this->model->where('name', $name)->update();
}
}
My blade form:
{!! Form::model(config('settings'), ['class' => 's-form', 'route' => ['setting.update']]) !!}
{{ method_field('PUT') }}
<div class="s-form-item text">
<div class="item-title required">Título do artigo</div>
{!! Form::text('title', null, ['placeholder' => 'Nome do site']) !!}
@if($errors->has('title'))
<div class="item-desc">{{ $errors->first('title') }}</div>
@endif
</div>
<div class="s-form-item s-btn-group s-btns-right">
<a href="{{ url('admin') }}" class="s-btn cancel">Voltar</a>
<input class="s-btn" type="submit" value="Atualizar">
</div>
{!! Form::close() !!}
But things does not work. How can I update the values into the table?
Solution :
See improved answer in Update 2
I would add a dedicated Service Provider for this. It will read all your settings stored in the database and add them to Laravels config. This way there is only one database request for the settings and you can access the configuration in all controllers and views like this:
config('settings.facebook');
Step 1: Create the Service Provider.
You can create the Service Provider with artisan:
php artisan make:provider SettingsServiceProvider
This will create the file app/Providers/SettingsServiceProvider.php
.
Step 2: Add this to the boot-method of the provider you have just created:
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
// Laravel >= 5.2, use 'lists' instead of 'pluck' for Laravel <= 5.1
config()->set('settings', AppSetting::pluck('value', 'name')->all());
}
From the Laravel Docs:
[The boot method] is called after all other service providers have been registered, meaning you have access to all other services that have been registered by the framework.
http://laravel.com/docs/5.1/providers#the-boot-method
Step 3: Register the provider in your App.
Add this line to the providers
array in config/app.php
:
AppProvidersSettingsServiceProvider::class,
And that’s it. Happy coding!
Update: I want to add that the boot-method supports dependency injection. So instead of hard coding AppSetting
, you could inject a repository / an interface that is bound to the repository, which is great for testing.
Update 2: As Jeemusu mentioned in his comment, the app will query the database on every request. In order to hinder that, you can cache the settings. There are basically two ways you can do that.
-
Put the data into the cache every time the admin is updating the
settings. -
Just remember the settings in the cache for some time and clear the cache every time the admin updates the settings.
To make thinks more fault tolerant, I’d use the second option. Caches can be cleared unintentionally. The first option will fail on fresh installations as long as the admin did not set the settings or you reinstall after a server crash.
For the second option, change the Service Providers boot-method:
/**
* Bootstrap the application services.
*
* @param IlluminateContractsCacheFactory $cache
* @param AppSetting $settings
*
* @return void
*/
public function boot(Factory $cache, Setting $settings)
{
$settings = $cache->remember('settings', 60, function() use ($settings)
{
// Laravel >= 5.2, use 'lists' instead of 'pluck' for Laravel <= 5.1
return $settings->pluck('value', 'name')->all();
});
config()->set('settings', $settings);
}
Now you only have to make the cache forget the settings key after the admin updates the settings:
/**
* Updates the settings.
*
* @param int $id
* @param IlluminateContractsCacheFactory $cache
*
* @return IlluminateHttpRedirectResponse
*/
public function update($id, Factory $cache)
{
// ...
// When the settings have been updated, clear the cache for the key 'settings':
$cache->forget('settings');
// E.g., redirect back to the settings index page with a success flash message
return redirect()->route('admin.settings.index')
->with('updated', true);
}
To avoid querying the database on each request, you should save the settings to a config file each time they are changed by the admin/user.
// Grab settings from database as a list
$settings = AppSetting::lists('value', 'name')->all();
// Generate and save config file
$filePath = config_path() . '/settings.php';
$content = '<?php return ' . var_export($settings, true) . ';';
File::put($filePath, $content);
The above will create a Laraval compatible config file that essentially just returns an array of key => values. The generated file will look something like this.
<?php
return array(
name => 'value',
name => 'value',
);
Any php file in the /config
directory will be auto-included by Laravel and the array variables accessible to your application via the config()
helper:
config('settings.variable_name');
You can store the data in the database just like you do it normally in Laravel. AppSetting::create()
, AppSetting::new()
and other methods.
For using the values in blade, you can do {{AppSetting::where('name','title')->pluck('value')}}
And, you can also use scopes for this.
class Setting extends Model
{
public function scopeFor($query, $settingName)
{
return $query->where('name', $settingName);
}
}
then you could use AppSetting::for('title')->pluck('value')
I want to share my use case, my answer may not be directly answering OP, but hope answering future developers.
This is tested in Laravel 8 application, but i believe it will work fine from Laravel version 5.5 and up.
In my case, I have a settings table with key and value fields as you may see in this migration file.
<?php
use...;
class CreateSettingsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('settings', function (Blueprint $table) {
$table->id();
$table->string('key')->unique();
$table->text('value');
$table->timestamps();
});
}
//...
}
I heavily use the values stored in this table in my application, so to gain on performance i store those key/value in a config file, I do that anytime the admin has updated a value in the back office.
For that purpose i use Eloquent model events, to be more precise I use saved
event, because the saving
/saved
events will dispatch when a model is created or updated.
<?php
namespace AppModels;
use...;
class Setting extends Model
{
use HasFactory;
//...
/**
* The "booted" method of the model.
*
* @return void
*/
protected static function booted()
{
static::saved(function () {
$settings = static::pluck('value', 'key')->toArray();
$stringify_settings = var_export($settings, true);
$content = "<?php return {$stringify_settings};";
File::put(config_path('app_settings.php'), $content);
});
}
}
I did one more thing, I added /config/app_settings.php
to .gitignore
file.