How to properly keep config files in Laravel? - php

I've built a piece of software which uses Laravel config module to consume certain settings.
Thing is, we're using Laravel Forge to auto-deploy, and everytime we deploy, configs are reset to the "blank" state, thus breaking some things everytime I deploy.
I have added the files to .gitignore, but doesn't seem to do the trick.
Can anyone point me towards the right direction in order to save this config files without having the re-set them everyime we deploy?
Thanks everyone!

It would be helpful to have an example of your config and .env files
Config files for multiple environments rely on .env files in each environment.
env() returns either the matching variable from your .env or the value specified.
so env('QUEUE_DRIVER', 'sqs') would look into the .env file for the QUEUE_DRIVER variable if it can't find a variable it returns the default 'sqs'.
An example of a queue config file might looks like this.
config/queue.php
<?php
return [
'default' => env('QUEUE_DRIVER', 'sqs'),
'connections' => [
'sync' => [
'driver' => 'sync',
],
'sqs' => [
'driver' => 'sqs',
'key' => env('SQS_KEY'),
'secret' => env('SQS_SECRET'),
'prefix' => env('SQS_URL'),
'queue' => 'general_queue',
'region' => 'us-east-1',
],
],
];
You would then set your variables in your .env file for each environment.
Production may look like this.
.env
QUEUE_DRIVER=sqs
SQS_KEY=yoursqskey
SQS_SECRET=yoursqssecret
SQS_URL=yoursqsurl
Your local environment might look like this.
.env
QUEUE_DRIVER=sync
You can edit your .env file in forge under Sites > Site Details > Environment

Related

Laravel - Nexmo not picking up credentials in .ENV file

I recently added laravel/nexmo-notification-channel to my laravel project which also installed Nexmo/nexmo-laravel.
After installing, I published vendor files so that I get config/nexmo.php and in there I noted that it looks in the .env file for NEXMO_KEY and NEXMO_SECRET.
So I went ahead and created these within my .env file
NEXMO_KEY=[my_key]
NEXMO_SECRET=[my secret]
NEXMO_SIGNATURE_SECRET=[my signature secret]
After this, I added Nexmo to my service providers in app.php:
'providers' => [
...,
Nexmo\Laravel\NexmoServiceProvider::class
]
and also added the following in config/services.php:
'nexmo' => [
'key' => env('NEXMO_KEY', ''),
'secret' => env('NEXMO_SECRET', ''),
'sms_from' => '[my number]'
],
But I still get the following error when thrying to send an SMS using the use Illuminate\Notifications\Messages\NexmoMessage; class:
"message": "Provide either nexmo.api_secret or nexmo.signature_secret",
I can use these same credentials to send an SMS from CLI, so why can't I send it from laravel?
There have been a couple of workarounds for this that are valid, but at first glance it looks like the Nexmo package does the work to bring in the ENV secrets into Laravel's config. Because of caching problems, you should never call env() within Laravel, instead you should be using config() - so in this case, config(nexmo.api_secret).
My main point here though is that I can't look into the "correct" solution for you because the package is abandoned. Nexmo is no longer Nexmo, it's Vonage, and Laravel core team have subsequently updated the notification-channel package.
For supported use to integrate Vonage services (SMS), please use the following package:
https://github.com/laravel/vonage-notification-channel
I'm not sure exactly why, but, Vonage/Nexmo doesn't pick details from the .ENV.
Instead, use a global constant to fetch the secrets:
Create a global.php file in the config folder, and add your secrets from the env like this:
<?php
return [
// Other constants values
'SMS_API_KEY' => env('SMS_API_KEY', ''),
'SMS_API_SECRET' => env('SMS_API_SECRET', ''),
]
?>
Then, you can use the constants in your controller as usual:
'key' => config('global.SMS_API_KEY'),
'secret' => config('global.SMS_API_SECRET')
then: recache, php artisan config:cache

HTTP request from a Laravel app on one Apache virtual host to a Lumen app on sibling virtual hosts: MySQL Access denied for user 'root'#'localhost' [duplicate]

I am developing an API service that another site I've developed will be using. So locally when building and testing, obviously I want both local copies of the site to work. However, it seems to mix up the environment variables.
For example:
Site A has APP_URL=http://a.local
Site B has APP_URL=http://b.local
I send a GET Request (using Guzzle) from Site A code to http://b.local/test
The /test endpoing in Site B simply dumps out dump(env('APP_URL'))
Result retrieved by Site A is "http://a.local"
Expected result: "http://b.local"
So the code in Site B is running with environment variables loaded from Site A. This is an issue as Site B cannot access the correct database, it's trying to use the Site A's database.
Is this an issue with my local setup (Win10 + WAMP), PHP settings, Laravel settings?
I also encountered this issue, and it is mentioned here. The resolution for it is to run php artisan config:cache in both projects to cache configuration from .env files or patch the code from here.
are you using artisan commands to run both projects with different ports ?
php artisan serve --port=8000
php artisan serve --port=8010
You can set Environment variables in either the vhost config OR in an .htaccess file:
SetEnv APP_URL http://b.local
Apart from #Daniel Protopopov answer above there is also another way, that is also works when both Site A and Site B are Lumen.
In short just rename your DB_DATABASE variable on each side to a different name. Then change the respective variable names in the respective config/<configfilename>.php files.
So that on Site A you would have SITE_A_DB_DATABASE in .env and matching 'database' => env('API_A_DB_DATABASE', 'forge'), line in config/database.php.
Then your Site B SITE_B_DB_DATABASE will not be overwritten due to variable names are different.
The same solution applies for any .env variables which names match.
Because the command php artisan config:cache doesn't work here (closure needed in routes file config file)
LogicException : Your configuration files are not serializable.
I add phpdotenv with composer :
composer require vlucas/phpdotenv
And at the begginning of the file "/bootstrap/app.php" (after "new Illuminate\Foundation\Application"), I add :
$app->detectEnvironment(function () {
$dotenv = Dotenv\Dotenv::create(__DIR__ . '/../', '.env');
$dotenv->overload();
});
Maybe an alternative
If you are calling a Lumen 8 API from within a Laravel 6 application using GuzzleHttp and the Laravel env is being inherited to Lumen, creating config file worked for me.
In bootstrap/app.php comment below lines to prevent loading current env values from Laravel
// (new Laravel\Lumen\Bootstrap\LoadEnvironmentVariables(
// dirname(__DIR__)
// ))->bootstrap();
In bootstrap/app.php add below line after $app has been created.
$app->configure('database');
Create config/database.php in lumen root folder. Return all env values needed for Lumen api in an array in the config file.
<?php
return [
'timezone' => 'UTC',
'default' => 'pdbmysql',
'connections' => [
'pdbmysql' => [
'driver' => 'mysql',
'host' => 'localhost',
'port' => '3306',
'database' => 'db2',
'username' => 'root',
'password' => 'root',
],
],
];

WAMP Laravel - Sending API requests from one local site to another mixes up environment variables

I am developing an API service that another site I've developed will be using. So locally when building and testing, obviously I want both local copies of the site to work. However, it seems to mix up the environment variables.
For example:
Site A has APP_URL=http://a.local
Site B has APP_URL=http://b.local
I send a GET Request (using Guzzle) from Site A code to http://b.local/test
The /test endpoing in Site B simply dumps out dump(env('APP_URL'))
Result retrieved by Site A is "http://a.local"
Expected result: "http://b.local"
So the code in Site B is running with environment variables loaded from Site A. This is an issue as Site B cannot access the correct database, it's trying to use the Site A's database.
Is this an issue with my local setup (Win10 + WAMP), PHP settings, Laravel settings?
I also encountered this issue, and it is mentioned here. The resolution for it is to run php artisan config:cache in both projects to cache configuration from .env files or patch the code from here.
are you using artisan commands to run both projects with different ports ?
php artisan serve --port=8000
php artisan serve --port=8010
You can set Environment variables in either the vhost config OR in an .htaccess file:
SetEnv APP_URL http://b.local
Apart from #Daniel Protopopov answer above there is also another way, that is also works when both Site A and Site B are Lumen.
In short just rename your DB_DATABASE variable on each side to a different name. Then change the respective variable names in the respective config/<configfilename>.php files.
So that on Site A you would have SITE_A_DB_DATABASE in .env and matching 'database' => env('API_A_DB_DATABASE', 'forge'), line in config/database.php.
Then your Site B SITE_B_DB_DATABASE will not be overwritten due to variable names are different.
The same solution applies for any .env variables which names match.
Because the command php artisan config:cache doesn't work here (closure needed in routes file config file)
LogicException : Your configuration files are not serializable.
I add phpdotenv with composer :
composer require vlucas/phpdotenv
And at the begginning of the file "/bootstrap/app.php" (after "new Illuminate\Foundation\Application"), I add :
$app->detectEnvironment(function () {
$dotenv = Dotenv\Dotenv::create(__DIR__ . '/../', '.env');
$dotenv->overload();
});
Maybe an alternative
If you are calling a Lumen 8 API from within a Laravel 6 application using GuzzleHttp and the Laravel env is being inherited to Lumen, creating config file worked for me.
In bootstrap/app.php comment below lines to prevent loading current env values from Laravel
// (new Laravel\Lumen\Bootstrap\LoadEnvironmentVariables(
// dirname(__DIR__)
// ))->bootstrap();
In bootstrap/app.php add below line after $app has been created.
$app->configure('database');
Create config/database.php in lumen root folder. Return all env values needed for Lumen api in an array in the config file.
<?php
return [
'timezone' => 'UTC',
'default' => 'pdbmysql',
'connections' => [
'pdbmysql' => [
'driver' => 'mysql',
'host' => 'localhost',
'port' => '3306',
'database' => 'db2',
'username' => 'root',
'password' => 'root',
],
],
];

Laravel ENV variable collision in a Kubernetes cluster

I came to a very specific case by using Laravel framework as a part of a kubernetes cluster. These are the facts, which have to be known:
I've created a Docker container for caching called redis
I've created a Docker container for application called application
These two work together in a Kubernetes cluster
Kubernetes is setting ENV variables in each Docker container. Commonly, one is called {container-name}_PORT. Therefore, Kubernetes has created the ENV variable REDIS_PORT in my application container, which is set to something like that: tcp://{redis-container-ip}:{redis-container-port}.
Laravel sets this ENV variable too, but use it as a standalone port variable like 6379. However, in this specific case, Redis does not work in Laravel, because of overwritten REDIS_PORT variable. The framework try to fetch redis on this example host string inside Kubernetes: tcp://redis:tcp://10.7.240.204:6379. Laravel logic behind: {scheme}://{REDIS_HOST}:{REDIS_PORT}. You can see, REDIS_PORT is filled with tcp://10.7.240.204:6379.
What is preferable to solve the issue?
In my opinion, Kubernetes uses the ENV variable for {container-name}_PORT in a wrong way, but I do understand the internal logic behind Kubernetes ENV variables.
At the moment, I have changed my config/database.php configuration in Laravel, but this causes a review of changelogs on every update.
Some of other details can be read here: https://github.com/laravel/framework/issues/24999
#Florian's reply to himself on github:
My solution was to change the config in config/database.php like that:
'redis' => [
'client' => 'predis',
'default' => [
'scheme' => 'tcp',
'host' => env('REDIS_SERVICE_HOST', env('REDIS_HOST','127.0.0.1')),
'port' => env('REDIS_SERVICE_PORT', env('REDIS_PORT',6379)),
'password' => env('REDIS_PASSWORD', null),
'database' => 0,
],
],
Now, the config checks first, if the REDIS_SERVICE_HOST and REDIS_SERVICE_PORT are present as ENV variable. This is the case, if you have a container in a docker/kubernetes cluster which is called REDIS.
Advantage of this solution is, that REDIS_SERVICE_HOST returns the IP address of the container, not a hostname. Therefore, there is no dns resolution anymore for this internal connections.

database.php file from environment directory not being loaded in Laravel 4

I am trying to load the local version of my database.php file located in my app/config/local directory.
I have setup my $env environment detection in start.php for local.
$env = $app->detectEnvironment(array(
'local' => array('your-machine-name')
));
The correct environment appears to be detecting correctly as the result of using:
App::environment('local')
evaluates as TRUE, however it only loads the default database.php in the app/config directory.
Just in case it was still related to detection I have tried just hardcoding local as the environment, but it has the same effect.
$env = $app->detectEnvironment(function()
{
return 'local';
});
I also tried using a different name for the environment in case 'local' had some undocumented reserved meaning.
I have successfully setup environments in other projects using Laravel 4, and I can't work out for the life of me what is different in this case. I'd appreciate any suggestions on what could lead to this behaviour.
The local environment is run on MAMP.
I just did an additional test and found that app.php file in my local folder loaded correctly. It is only the local database.php file that does not appear to be loading.
Production config files are loaded first and then merged with overrides from other environments. If the production file generates an error (e.g. undefined index) the config loading will bail early without loading the overrides. Check whether it's generating an error in the log. If so, in the production config file, check the value is set before attempting to use it and the local config file will then load correctly.
In your project inside app/config directory you should create a directory named local and then in that directory you should create a file named database.php and in that fole you should provide the configuration, for example:
// File: app/config/local/database.php
return array(
'connections' => array(
'mysql' => array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'myTestDb', // myTestDb is a db name for example
'username' => 'root',
'password' => '',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
'pgsql' => array(
'driver' => 'pgsql',
//...
),
),
);
Then in your project_folder/bootstrap/start.php file use something like this:
$env = $app->detectEnvironment(array(
'local' => array('*.dev', gethostname()),
'production' => array('*.com', '*.net')
));
You may also check this answer for environment setup. This should work.

Categories