Laravel: Update .env file by publishing a third-party package - php

I have a library which I want to wrap into Laravel package.
My library uses two configs: the public config.php for some nonsensitive settings and .env private config for sensitive credentials.
I'd like to vendor:publish my configs for end user. And it seems fine for public config.php but how to publish my .env in Laravel-friendly way? I failed to find any way to do it by vendor:publish.

The application's .env file is primarily there for keeping sensitive information out of configuration files and other resources that often get committed to source control. It's not intended to be published in any way.
What you can do is create a separate configuration file with some sensible defaults preset, while at the same time allowing the user to override them. For example:
// my-config.php
return [
'user_model => env('MY_USER_MODEL', App\User::class),
...
];
If needed, they can implement their own User model or omit setting it within their own env file and defaulting to the implementation you've specified.
You'll see this approach quite often in packages providing roles, permissions, tenancy, etc.

Related

Symfony 5 global dynamic configuration file

I'm a long time Zend Framework user (now renamed Laminas). But I decided to give a try to last Symfony version. So I just installed it in 5.1.2.
I'm facing a question regarding the multiple environments deployments. In my compay, we have :
Local environment which is developer pc.
Development.
Staging.
Production.
In ZF-Laminas, we have a global.php file which is located in config directory.
For those of you who are not familiar with this framework, you can override key set in global.php file by creating local.php file.
In this global file, I use to put standard configuration for my application.
For example (prod) :
'open_id' => [
'client_id' => 1234
]
Then, I have development and staging files which car override those values for every environmenet. During the deployment, the file corresponding to the environment is copied to local.php.
Let's say staging.local.php.dist becomes local.php with :
'open_id' => [
'client_id' => 5678
]
Which is fine because value is overriding the one from global file.
I would like the same behavior in Symfony but I don't see something similar in Symfony 5.
So far, I only found two possibilities
Create a bundle which will allow me to have a <bundle_name>.yaml file in config/packages directory. According to the documentation (https://symfony.com/doc/current/configuration.html#configuration-files), I will be able to have dev, prod and staging overrides. But it forces me to create a bundle to handle just some standard configurations, which is huge.
Use .env files. But .env files only allow string data, not complex data like arrays.
What do I miss ? Or is it my "zend" way of doing things that is wrong ?
Thanks.
You can also create services_%env%.yaml (services_dev.yaml, services_test.yaml) files for each environment. It will allow you to define different parameters and override/define services for each environment.
Example:
config/services_dev.yaml
parameters:
hello: 'world'
From what I understand from your post, your goal is to have different config values based on the server you are on. If this is the case, you can use environment variables (in the .env file or .env.local for server specific config). You can then use these values in your applications by binding the env var to a parameter. This parameter will then be available within the configuration by using %parameter_name% as value or within the container. You can also pas parameters to services (service definitions are handled the same way as any other config). For more information you can checkout these sources:
https://symfony.com/doc/current/configuration/env_var_processors.html
https://symfony.com/doc/current/configuration.html

Laravel: Join two application by one config

My project is two Laravel applications in one folder. Why two separate applications instead of one? I have good reasons. Anyway, for example, every time I want to change the app name in the config (config/app.php) I go and edit the .env file in both directories (of the two applications) and then execute artisan config:cache to update the cached config.
It's not much of a task or anything, but it's a bad design I believe. So, I am looking for a way to take the values shared between these two application out to a separate file. And have these application load this file and override/apply the values inside it to the app configuration.
So, now I have a config.php in the root directory (which holds the other two apps in /app1 and /app2). And inside each app's AppServiceProvider I call the config.php and loop through the values and set each using Config::set(..., ...).
This worked for me well, but of course changing the values loaded in the \Config package doesn't change the values that were fetched from it earlier to this point. For example app()->environment() returns the value set in the config/app.php, not the new value introduced in the global config.php. That's because the App library asked for the env property before I could override it!
So, what I want your help with is: you either tell me about a more smart/standard way to achieve 1 config for 2 apps setup. Or tell me where to put the code that overrides the app config with the new values from my global config.php (currently I put the code in register() in App\Providers\AppServiceProvider)
You can share env settings by removing one of .env files and make a symlink to the other file instead of a common file. In this case if you change a file, both applications get changed values.

How Can I Configure Lumen To Broadcast Events via Pusher?

Lumen's docs state that "Lumen supports several broadcast drivers out of the box: Pusher, Redis, and a log driver for local development and debugging. A configuration example is included for each of these drivers. The BROADCAST_DRIVER configuration option may be used to set the default driver."
In my .env file I have set BROADCAST_DRIVER=pusher. Where/how can I configure my pusher ID, key, and secret? I see that in Laravel a configuration file for setting these options lies within config/broadcasting.php. Where can I set these options within Lumen?
Temporarily I have edited Illuminate\Broadcasting\BroadcastManager and hard coded my values in.
protected function createPusherDriver(array $config)
{
// override
$app_id = 'hidden';
$key = 'hidden';
$secret = 'hidden';
return new PusherBroadcaster(
new Pusher($key, $secret, $app_id, Arr::get($config, 'options', []))
);
}
Okay, I figured it out. Essentially you have to add in the config files yourself.
Create a config directory in the root of your app.
Copy config/broadcasting.php from a working laravel installation into this directory
Add the following keys to your .env file: PUSHER_SECRET, PUSHER_KEY, PUSHER_APP_ID
In general, Lumen supports two modes of configuration:
Setting environment variables consumed by Lumen's internal config files
Creating project config files that override Lumen's internal configuration
Lumen provides environment-based configuration variables needed to configure most of the framework's components, including Pusher. Though unclear from the docs, we can also configure Lumen through config files like Laravel. This enables advanced configuration that Lumen may not support through its built-in configuration structure.
By default, new Lumen projects don't provide configuration files like new Laravel projects do in the config/ directory. As #Feek discovered, we can create the config/ directory and add any needed config files. For example, we can create the config/broadcasting.php file to set up broadcast connections.
When creating a config file in the project like this, Lumen will automatically read configuration values from the file if it matches the name of one of the Lumen built-in config files. If we want to add a custom configuration file that doesn't match one of Lumen's internal config filenames, we need to manually instruct Lumen to read the config file in a service provider or in bootstrap/app.php.
For instance, to load configuration values from config/my-custom-config.php, add this line to the application's boot process:
$app->configure('my-custom-config');
In the particular case of this question, Lumen's built-in broadcasting.php config file reads Pusher environment variables for us, so we don't need to create a config file in the project for these. Simply set the BROADCAST_DRIVER, PUSHER_SECRET, PUSHER_KEY, and PUSHER_APP_ID in .env.

Finding the project root from within a composer package

I'm trying to provide potential locations of a config file within my package: .config.yml
At present, I've loaded an array within one of my classes with some typical locations:
protected $configDirectories = [
'./',
'./config',
'./app/config',
'./config',
'./vendor/name/packagename/config'
];
Problem is; my package is loaded into ./vendor/name/packagename and of course, ./ doesn't know how to get to the project root.
The aim is to allow users of this package to just drop .config.yml into any of the pre-specified directories and it should be picked up. How can I achieve this?
I had a similar situation. In my case, the front-end controller was in ./. So, I required the user of my package to do something like ...
\Wonderful\Package\Init::setRootDirectory(__DIR__);
(But I eventually decided that instead of having magic search order happening under the covers to locate the config file, I ended up having the one (or more) config files specified explicitly (can be anywhere with any name) ...
\Wonderful\Package\Init::loadConfigFile(__DIR__.'/config.yml');
\Wonderful\Package\Init::loadConfigFile(__DIR__.'/config.DEV-overrides.yml');
If you want to give the user the ability to configure your bundle, you MUST do it via semantic configuration and not via a specified and own config file. Do it the Symfony way.

How to have environment specific .env files for dotenv (in Laravel 5)

I've just started using Laravel 5 which uses the dotenv library. This uses a .env file in the root of the project which sets the environment with this line:
APP_ENV=local
According to everything I've read on the subject, all other environmental specific configuration should be placed in this file, so database passwords, urls etc, which are then read into the main config array like this:
env('DB_HOST', 'localhost')
While I feel this may work for a few specific things like database passwords that you might not want committed, what I really want is to be able to commit most or all of my different environmental values for each environment.
Thus what I want is for .env to define APP_ENV as "local", "staging" or "production" and then have a .local.env or .env.local file containing the values, which I can then commit and the correct file will be loaded based on APP_ENV.
Is this possible? Laravel 4 had the cascading config arrays which seemed a lot more flexible but if I can have an environmental .env file then I can live with that.
Solved it in the end by modifying app/Providers/ConfigServiceProvider.php. This file is added as a stub to your app folder when you create a project and is intended for overriding config values.
It now handles the cascading configs, so that any values in config/local/app.php for example will override config/app.php. As the comment below says it doesn't handle matching arrays in the environment config and will just replace then. But I can solve that when I need it.
<?php namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Symfony\Component\Finder\Finder;
class ConfigServiceProvider extends ServiceProvider {
/**
* Overwrite any vendor / package configuration.
*
* This service provider is intended to provide a convenient location for you
* to overwrite any "vendor" or package configuration that you may want to
* modify before the application handles the incoming request / command.
*
* Modified 2014-01-20 to allow environment specific configs to be loaded
* from app/config/[environment]/ which will cascade over the base configs.
*
* #return void
*/
public function register()
{
$config = app('config');
$envPath = app()->configPath() . '/' . getenv('APP_ENV');
foreach (Finder::create()->files()->name('*.php')->in($envPath) as $file)
{
$configName = basename($file->getRealPath(), '.php');
$oldConfigValues = $config->get($configName);
$newConfigValues = require $file->getRealPath();
// Replace any matching values in the old config with the new ones.
// Doesn't yet handle matching arrays in the config, it will just replace them.
$config->set($configName, $newConfigValues + $oldConfigValues);
}
}
}
You dont have to use .env for everything. There are a few options.
Option 1 - Use only .env for a variable
'default' => env('DB_CONNECTION'),
Option 2 - Use only .env for a variable, but have a system default if none exists
'default' => env('DB_CONNECTION', 'mysql'),
Option 3 - just hard code your variable and not make it settable via the .env
'default' => 'mysql',
Option 2 is probably the best for most config options. You still define (and commit) an option for your config to your git repo - but you can easily override it in any .env file in the future if you want.
Option 1 is best specifically for passwords, app keys etc - so they are never committed to your git repo.
Option 3 is for a few config variables which you know will just never change.
Note - the cascading Laravel 4 config folder option is no longer available.
It is easy to configure Laravel 5 environment.
Open your root application folder and find ".env.example",
Copy and rename into ".env",
Please fit ".env" file into your environment,
If you use GIT, make sure you don't push this file to your GIT repository.
For 'complete explanation', I write this configuration here.
I quote from the dotenv developer;
phpdotenv is made for development environments, and generally should
not be used in production. In production, the actual environment
variables should be set so that there is no overhead of loading the
.env file on each request. This can be achieved via an automated
deployment process with tools like Vagrant, chef, or Puppet, or can be
set manually with cloud hosts like Pagodabox and Heroku.

Categories