37

I'm using a package within my project and it stores a setting inside config/packagename

I would like to dynamically change this value inside the config file, this is how the file structure looks currently;

<?php

return [
    'view_id' => '118754561',

    'cache_lifetime_in_minutes' => 60 * 24,
];

I would like to change it to something like this -

'view_id' => Auth::user()->id,

Can you do this within the config file, or do you have to store some sort of variable to be updated later within a controller. Is there a way to place these variables in an env file and access these new variables from a controller?

alepeino
  • 9,551
  • 3
  • 28
  • 48
Courtney Ball
  • 481
  • 1
  • 4
  • 10
  • Are you use Sentry ? – Daebak Sep 18 '16 at 22:00
  • Context would be great for what you are trying to do. Based off of what you're showing me, yes this is possible. – Derek Pollard Sep 18 '16 at 22:00
  • which Laravel version are you using ? – Daebak Sep 18 '16 at 22:02
  • Apologies using Laravel 5.2 I'm trying to update a static ID set in a config file to one stored in a database. – Courtney Ball Sep 18 '16 at 22:13
  • first you should to check if user is well log in if (Auth::check()) { // The user is logged in... } than from laravel 4.2 Auth::id(); – Daebak Sep 18 '16 at 22:24
  • But you can't write that code from within a config file it throws an error 500 – Courtney Ball Sep 18 '16 at 22:30
  • The config is read too early in the process for the session (which auth uses) to be available,. You can set that config at run time any time after the session has started though. `Config::set(...)` – lagbox Sep 19 '16 at 00:46
  • Can you provide an example of this? – Courtney Ball Sep 20 '16 at 12:26
  • Which package are you using? – Gaurav Dave Sep 20 '16 at 12:59
  • Using Laravel 5.2 and the following package spatie laravel-analytics – Courtney Ball Sep 20 '16 at 16:15
  • 2
    Hi Courtney, it seems like you are trying to treat part of your context (like user, language, customer id) as a config parameter. It might look as a good idea, however it has lots of drawbacks - let's say you want to send an emails from cronjob to multiple users. I'm suggesting you to pass your context (like userId) from the controllers to services (and deeper) directly, it might be done by just $userId argument or using some sort of Context object which will contain the scope, so your code will rely not on global settings, but on directly passed context. – Ilia Kondrashov Oct 01 '16 at 03:45
  • have you try this https://laracasts.com/discuss/channels/general-discussion/dynamic-config-files-loading-in-laravel-5 – channasmcs Oct 05 '16 at 04:17
  • Hi All, I have provided with a way to solve this issue. This could be the easy method to solve the problem in-spite of the others who has answered the questions. Since we can set the config file dynamically on the fly. Happy coding :) – Naresh Kumar P Oct 06 '16 at 11:35
  • config(['packagename.view_id' => Auth::user()->id]); – Kundan roy Jan 25 '19 at 11:27

9 Answers9

34

This also is a generic solution to dynamically update your .env file (respective the individual key/value pairs)

  1. Change the setting in your config/packagename like so:
return [
    'view_id' => env('VIEW_ID', '118754561'),
    etc...
]
  1. Add an initial value into .env:

    VIEW_ID=118754561

  2. In an appropriate controller (e.g. AuthController), use the code below and call the function like this: updateDotEnv('VIEW_ID', Auth::User()->id)

    protected function updateDotEnv($key, $newValue, $delim='')
    {
    
        $path = base_path('.env');
        // get old value from current env
        $oldValue = env($key);
    
        // was there any change?
        if ($oldValue === $newValue) {
            return;
        }
    
        // rewrite file content with changed data
        if (file_exists($path)) {
            // replace current value with new value 
            file_put_contents(
                $path, str_replace(
                    $key.'='.$delim.$oldValue.$delim, 
                    $key.'='.$delim.$newValue.$delim, 
                    file_get_contents($path)
                )
            );
        }
    }
    

(The $delim parameter is needed if you want to make this function more generic in order to work with key=value pairs in .env where the value has to be enclosed in double quotes because they contain spaces).

Admittedly, this might not be a good solution if you have multiple users at the same time using this package in your project. So it depends on what you are using this package for.

NB: You need to make the function public of course if you plan to use it from other classes.

matthiku
  • 3,610
  • 1
  • 15
  • 21
  • What about if I have config values as an array? i.e something like `'cavPref' => ['F','C','R','G','H','E']`? – SaidbakR Oct 05 '17 at 23:09
26

All configuration files of Laravel framework stored in the app/config directory.

so if we need to create custom configuration values it would be better to keep separate our custom configuration in custom file. so we need to create custom file in app/config directory.

Laravel auto read this file as a config file and will auto manage it In this topic we are working with custom configuration in laravel and get configuration value in controller or view.

Now i am going to explain how to create a custom config file in Laravel so that we can implement dynamic feature over to this.

create a file in app/config/custom.php which have config keys and value like:-

return array(
  'my_val' => 'mysinglelue',
  'my_arr_val' => array('1', '2', '3'),
);

Now need to get these config values in view/controller so we will use Config class get() method for this

Syntax:

echo Config::get('filename.arraykey');

where filename is the config file’s name, custom in our case, and key is the array key of the value you’re wanting to access.

In Our case it will be as:

echo Config::get('custom.my_val');

Create run time configuration in laravel :-

Configuration values which are set at run-time are will set for the current request, not be carried over to subsequent requests.

You can pass the dynamic values over here so that you can modify the config file dynamically over here using the isset() functions.

Like how the @Kundan roy as suggested using of the isset() the same condition applies here to. But this one is the alternative method that will work for the dynamic setting of the values in the config.

Config::set('custom.my_val', 'mysinglelue');

Hence by using this method you can create the dynamic config files based on the values that you need.

Naresh Kumar P
  • 4,127
  • 2
  • 16
  • 33
  • This should be higher up. Laravel specifically has `Config::set()` for these kind of scenarios. – Andrei Oct 06 '16 at 11:15
  • 1
    First, this creates config *values*, not config *files*. Second, this doesn't address the issue that the config values as written in the file are read at the start of the Laravel app lifecycle. So, any service providers that depend on these values will use the original value, not the one you set with this method or otherwise. My answer (http://stackoverflow.com/a/39778179/3208258) attempted to handle these cases. – alepeino Oct 06 '16 at 12:34
  • 2
    What you mention is right. But in my project i have dynamically set the config values only with the help of the `Config::set()` method and it works to the perfect. Hope so you have all the other alternatives over to the question. I suggest this method. That's it. I am sure that this will work for dynamic configuration in the laravel. – Naresh Kumar P Oct 07 '16 at 01:21
  • 1
    this does not overwrite the value right? so after the lifecycle of the request the config value is set to the original value – shigg Nov 20 '18 at 12:29
9

If you want to actually edit the config files (either config/packagename.php or .env) then you may follow matthiku's answer.

However, if I were you, I guess I'd rather want to configure this 3rd party package based on some value defined at runtime, instead of modifying any file (which by the way won't take effect until the next request, when the env values are read again).

So, in my opinion the cleanest way to do this is:

  • store your desired value in the config data:

    config(['packagename.view_id' => Auth::user()->id]);

  • However, you may notice this probably won't work: the service provider which provides the service you need is often registered before the request is processed, that is, before your config change takes place. So you are still getting the service with old values config.

  • So, how could you have the service provider be called only when needed and not before (that is, after setting the new config value)? You could make it a deferred provider. Following your example of "spatie laravel-analytics", replace in config/app.php this line:

    Spatie\Analytics\AnalyticsServiceProvider::class

    with this one:

    App\Providers\AnalyticsDeferredServiceProvider::class

    and finally create the App\Providers\AnalyticsDeferredServiceProvider class, with:

:

<?php
namespace App\Providers;

use Spatie\Analytics\Analytics;
use Spatie\Analytics\AnalyticsServiceProvider;

class AnalyticsDeferredServiceProvider extends AnalyticsServiceProvider
{
    protected $defer = true;

    public function provides()
    {
        return [Analytics::class];
    }
}

This way you can have the provider read the config values when you are about to instantiate the service, after you set any runtime config values.

Community
  • 1
  • 1
alepeino
  • 9,551
  • 3
  • 28
  • 48
  • Did anyone try this solution? I have exactly the same problem. – Juan Pablo Fernandez May 18 '17 at 15:47
  • How can i implement this solutions change session lifetime value at user level? What i want is to apply different session lifetime for different users (depending on user type value from database). – Jay Pandya Nov 15 '17 at 12:18
9

Since Laravel v5.2 you can dynamically set config values this way:

<?php

config(['app.timezone' => 'America/Chicago']);

$value = config('app.timezone');

echo $value;
// output: 'America/Chicago'
lasec0203
  • 2,422
  • 1
  • 21
  • 36
8

Use this in controller when you need to change.

  <?php

    use Illuminate\Support\Facades\Config;

     //[...]

    $user_id =  Auth::user()->id; 

    Config::set('view_id', $user_id );
lasec0203
  • 2,422
  • 1
  • 21
  • 36
Shahid Chaudhary
  • 890
  • 3
  • 14
  • 25
3

You can do like this.

In your custom config file. Add the following code You can send your id dynamically from the query string.

'view_id' => isset($_REQUEST['view_id'])?$_REQUEST['view_id']:null,

To get view id

 echo config('app.view_id'); // app is config file name
TIGER
  • 2,864
  • 5
  • 35
  • 45
Kundan roy
  • 3,082
  • 3
  • 18
  • 22
  • Note that this solution would be problematic if you implementing Laravel config caching. https://laravel.com/docs/8.x/configuration#configuration-caching – Jason Nov 16 '20 at 16:14
1

config(['packagename.view_id' => Auth::user()->id]);

Kundan roy
  • 3,082
  • 3
  • 18
  • 22
-1

Actually if you are that point of code which forces you to make the config values dynamic, then there should be something wrong with your code flow, as the use of config file is just for initializing required values - which should be defined before the app is loaded.

Making config values dynamic is a "BAD PRACTICE" in the world of coding. So there is the following alternative for your problem.

Define value in .env file (optional)

VIEW_ID=your_view_id_here

Use value inside Controller

$auth_id = auth()->user()->id;
$view_id = env('VIEW_ID', $auth_id);
// If .env file doesn't contains 'VIEW_ID' it will take $auth_user as the view_id

Hope this helps you!

Saumya Rastogi
  • 13,159
  • 5
  • 42
  • 45
  • changing config values dynamically can be very helpful in unit testing, where a certain test requires 1 or 2 config values set to enabled functionality for the test to pass. These 1 or 2 config values would otherwise not be set normally. Outside of testing, I can see this being a Bad Practice – lasec0203 Aug 14 '18 at 04:43
  • I don't agree with it being a bad practice as making custom config files that can be dynamical changed can be useful when your client is still unsure as of things like contact address, official email etc and saving stuff like this in the data base will require unnecessary querying and need i say a waste of an sql table. – Bobby Axe Sep 15 '19 at 16:57
-1

config::set() doesn't works for me in laravel 8. but I got best answer for Create or edit Config file

config(['YOUR-CONFIG.YOUR_KEY' => 'NEW_VALUE']);
$text = '<?php return ' . var_export(config('YOUR-CONFIG'), true) . ';';
file_put_contents(config_path('YOUR-CONFIG.php'), $text);

just try this way this works for me.

original answer you can see here

Harsh Patel
  • 1,032
  • 6
  • 21