Overriding configuration files of composer packages in Lumen - php

I have a Lumen project with external Composer packages installed. As usual with Lumen, they're stored in the vendor directory, each in their respective folder. Some of these packages have configuration files, which I would like to override with custom ones.
I have registered the files in my bootstrap/app.php using $app->configure() right after I register the application itself, so it looks like this:
require_once __DIR__ . '/../vendor/autoload.php';
try {
(new Dotenv\Dotenv(__DIR__ . '/../'))->load();
} catch (Dotenv\Exception\InvalidPathException $e) {
//
}
$app = new Laravel\Lumen\Application(
realpath(__DIR__ . '/../')
);
$app->withFacades();
$app->withEloquent();
$app->configure('/Configuration/Lumen/app.php');
$app->configure('/Configuration/Lumen/auth.php');
$app->configure('/Configuration/Tymon/jwt.php');
The files are present in their respective directories, and contain the settings I want Lumen to use instead of the defaults, which are located, respectively, at:
/vendor/laravel/lumen-framework/config/app.php
/vendor/laravel/lumen-framework/config/auth.php
/vendor/tymon/jwt-auth/config/config.php
The problem I run into is that with this configuration, Lumen seems to ignore my custom files, and instead uses the defaults. What am I doing wrong here?

Put your configuration files in config/ and register them in bootstrap/app.php by their filename, without the .php file ending.
// Your custom config in config/jwt-auth.php
$app->configure('jwt-auth');

I don't think any of the above answers is truly answering what the OP wanted to know how to do.
What they appear to want, is to load a composer package and register that packages configuration into the app without having to do any kind of manual configuration.
Sort of like when you import a standard composer package which builds a logger using environment variables and autoconfigures its setup without having to add that configuration to the app. So then things are simpler.
Although I'm assuming the OP knows that this leads to a few problems, in that you're stuck with a composer package configuring your app, with a few options to override those settings locally.
But I assume you're happy with that. So therefore, I'd like to propose this solution
In your composer package, create a providers folder, then add this code into a lumen service provider class, in my case I've called it TestProvider
<?php declare(strict_types=1);
namespace YourLibrary\Providers;
class TestProvider extends \Illuminate\Support\ServiceProvider
{
public function boot()
{
// Because we're using 'require', this needs to be a valid path
$path = __DIR__.'/vendor_config.php';
// Get a configuration object from the service container
$config = app()->make('config');
// An example: Set into the 'app' configuration at a specific subkey
// just to show you can modify the default app configuration
$config->set('app.subkey', require $path);
error_log(json_encode(config('app')));
// An example: Set into the 'vendor.test' configuration at a specific subkey
$config->set('vendor.test', require $path);
error_log(json_encode(config('vendor')));
}
}
As you can see, you can use the dot notation for the first parameter to set() to insert your configuration into the applications config, but be careful with the naming cause in theory I guess you could override any setting like this, it could be that you end up overwriting the entire config('app') and all it's settings which would lead to a partially non-functioning app.
Then inside your bootstrap.php file in your app, you need to register this service provider, like so:
$app->register(YourLibrary\Providers\TestProvider::class);
I've tested it with an app I was working on locally and this works and I'm already using it for a library that has a very static configuration, everything is working pretty great.

Related

Laravel adding normal PHP package

I have a new Laravel 5.6 application. I wanted to see if I could an existing library (see link). The idea is that I could use the controller to parse the fit file and display the data in a view.
I have added the package adriangibbons/php-fit-file-analysis in my composer.json file.
Then the documentation mentions:
<?php
require __DIR__ . '/vendor/autoload.php'; // this file is in the project's root folder
$pFFA = new adriangibbons\phpFITFileAnalysis('fit_files/my_fit_file.fit');
?>
How can this be done in Laravel? Normally I would add something in the 'providers' section of my app.php but don't know how I can add the above snippet in there.
Any ideas?
Laravel already loads the Composer autoload file so can skip the require line. Adding a provider to the providers array in app.php allows Laravel specific packages to hook into Laravel features/config. Since this package is not Laravel specific you can just use it directly in your controller.
$pFFA = new \adriangibbons\phpFITFileAnalysis('fit_files/my_fit_file.fit');
Or a slightly more "Laravel" way
add use adriangibbons\phpFITFileAnalysis at the top of your controller. Then in the method add:
$pFFA = new phpFITFileAnalysis(storage_path('fit_files/my_fit_file.fit'));

Laravel 5 load env file based on .env.master?

I'm planing to do something like, specifying what env file to load during application bootstrap time by creating a variable in .env.master such as ENV_VER = dev.env
This is because I have several branches such as development, release-1.1 and etc. Thus by loading the env file based on the name specified in a master env file, developers no longer have to copy and paste new variables into their local copy of .env and instead, just specify what version of env file to load in the master env file. By the way, I have several env files such as dev.env, 1.6.env etc.
Is it possible?
Definitely, me myself I tend to "bend" a framework little bit everytime and there's always a way, not always the best solution though. I'm not giving a whole implementation here, just pointing you in some direction, that might work for you.
You can extend Laravel's base application class Illuminate\Foundation\Application, which contains $environmentFile variable storing environment file loaded during appplication bootstrap or possibly override function loadEnvironmentFrom($file) or environmentFile(). The whole logic is up to you.
So basically all you need to do in order to be able to "play" with .env loading is...
Create a new application class extending Laravel's one:
namespace MyNamespace;
...
use Illuminate\Foundation\Application as App;
/**
* I'm doing alots of magic with .env in this class
*/
class Application extends App
{
...
/**
* The environment file to load during bootstrapping.
*
* #var string
*/
protected $environmentFile = '.env.main';
...
}
And now, because we have a new bootstraping class, we have to tell Laravel we want to use it. So you'll have to modify bootstrap/app.php file in point where a new instance is being created:
...
$app = new MyNamespace\Application(
realpath(__DIR__.'/../')
);
...
Note: For inspiration I recommend you to really look at Illuminate\Foundation\Application class.
In laravel 5.5+ you can, maybe earlier, you can set your server have a APP_ENV environment or server variable that the process can see (apache, command line...)
this will allow you to use a suffix or file extension on your .env files for auto loading those files...
APP_ENV=dev :: .env.dev
APP_ENV=production :: .env.production
much easier than other solutions.
If you want to look into how this is done, it starts with
1. application bootstrappers
protected $bootstrappers = [
\Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
\Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
\Illuminate\Foundation\Bootstrap\HandleExceptions::class,
\Illuminate\Foundation\Bootstrap\RegisterFacades::class,
\Illuminate\Foundation\Bootstrap\SetRequestForConsole::class,
\Illuminate\Foundation\Bootstrap\RegisterProviders::class,
\Illuminate\Foundation\Bootstrap\BootProviders::class,
];
2. LoadEnvironmentVariables
first the environment is determined…
\Illuminate\Foundation\Bootstrap\LoadConfiguration::bootstrap calls
\Illuminate\Foundation\Application::detectEnvironment
If
--env={env} for CLI then it will use that for APP_ENV.
Else
\Illuminate\Foundation\EnvironmentDetector::detectWebEnvironment
is called which uses a callback…
function () use ($config) {
return $config->get('app.env', 'production');
}
where app.env defaults to env('APP_ENV', 'production')
3 LoadConfiguration
\Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::bootstrap calls...
\Illuminate\Foundation\Application::afterLoadingEnvironment
which eventually gets to
\Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::checkForSpecificEnvironmentFile
which sets the environment file based on app env IF the file exists.
$this->setEnvironmentFilePath(
$app, $app->environmentFile().'.'.env('APP_ENV')
);
allowing it to load the .env.{APP_ENV} instead of .env
NOTE: Testing.
when running php unit tests. the Illuminate/Foundation will try to load the .env.testing file for configurations!

Lumen : use config constant file from other folder

I have laravel and lumen running parallel on a server.
and structure is like
var/www/application/laravel
var/www/application/lumen
Now laravel app is already developed for full fledged website. And lumen folder is being used for webservices. Now there are many constant files in config folder like config>messages.php and I want to reuse those without rewriting it in lumen. But currently all I can see is I can access only lumen constants in lumen, cant access laravel constant file.
Such as config('messages.status'); can only access value when messages.php is in lumen.
Any idea how do I configure lumen code to include laravel config constants file too?
p.s. lumen version : 5.4, laravel version : 5.2
Thanks.
You can load all the Laravel app configs in your Lumen by making a new config file and requiring all files like this:
/var/www/application/lumen/config/custom.php
<?php
$path = '../../laravel/app/config/';
$config = [];
foreach ( scandir($path) as $filename ) {
$filePath = $path . '/' . $filename;
if (is_file($filePath)) {
$config += require_once $filePath;
}
}
return $config;
And then you can access them in your Lumen like this config('custom.key');.
That's right, there are predefined paths for configuration files. Take a look at vendor/laravel/lumen-framework/src/Application.php. There's a getConfigurationPath method there.
Basically, Lumen will try to load config files from your config folder, and if nothing is found then will load from /vendor/laravel/lumen-framework/config/*
I suggest you symlink them. As I don't see any way to modify Lumen core for this (actually, yes, you could override Application class and instantiate it in the bootstrap, but you should take care of things like the __DIR__ constant inside it).
UPDATE
Maybe it's easier. Take a look at this loop: Lumen: print custom config return NULL . The guy is loading every config file in a loop using $app->configure($file); method.
Actually, looks like the TheFallen solution here.

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.

Allow users of an opensourced project to add their own files to their copy

So I'm creating a semi-popular open source project and am looking for ways for its users to customize their copy.
Basically I've zero experience using Composer and next to none with git submodules. I have this file structure pushed to git:
/ROOT
----/subdirectory/
---------/another.file.php
----/main.class.php
----/config.default.php
It would be ideal for users to be able to copy config.default.php to the same directory, rename it to config.php (and by doing that override the default configuration values) - and I'd like them to be able to add their own files to the /subdirectory/ too, allowing them to extend the tool to their unique requirements.
My question is, don't those files get trimmed when pull (in the case of git submodule) or Composer update is performed? If so, how do I achieve the requirements with as little fuss for the end user as possible:
A single, optional, freely editable configuration file
Two directories that can contain files that users create
Above alterations stay within the users own version control system and are not removed when a new version is fetched.
Thank you for your patience in advance.
What most application frameworks/CMSs are doing these days is to split this process in two packages:
one library package (e.g. symfony/symfony, laravel/framework) that contains the bulk of the code, and that will be installed in vendor/
one "bootstrap" package (e.g. symfony/framework-standard-edition, laravel/laravel) that contains an application shell that your users can start from. That would contain default config and a composer.json that includes the library package + whatever else is needed in the "require" section. This bootstrap package is typically not updated via composer since it becomes the application/site of your users. Therefore it should contain as little code as possible, and be essentially only configuration.
You currently load your user config when your class loads:
if ( is_readable( KINT_DIR . 'config.php' ) ) {
require KINT_DIR . 'config.php';
}
If you added a public setConfig() property, then the config could be located anywhere, and your default would still work (code off the top of my wee head):
Public static function setConfig($config) {
if ( is_readable( $config ) ) {
require $config;
}
}

Categories