Fallback location for psr-0/4 autoloading - php

I'm building a PHP package and in it I have a folder (let's say /vendor/myvendor/packagename/src/Classes) which I want to autoload using PSR-4.
But I would also like to provide an option to copy that folder from its current location to the project root (let's say /packagename/Classes, something along the lines of Laravel's publish command).
So how could I go about autoloading it?
I would like Composer to first see if the folder exists under the app's root, and if it does then autoload that. Else fall back to the default location inside /vendor. Is that possible?
FWIW, this is Laravel specific package, which means that I could use Laravel's publish command to copy the entire folder where ever, but then
I would have to manually add the new location to autoload;
Even if I do, there would be namespace conflict between the old and new location.

I would like Composer to first see if the folder exists under the app's root, and if it does then autoload that. Else fall back to the default location inside /vendor. Is that possible?
Yes, it is possible.
You need to mention everything on your ServiceProvider for your package.
There are every informations about how to publish your views, assets in the docs and it fits your needs.
Have a look at the docs:
https://laravel.com/docs/5.3/packages#public-assets
I am copying some example for you over here:
If you want to publish your translations, you need to perform this task:
/**
* Perform post-registration booting of services.
*
* #return void
*/
public function boot()
{
$this->loadTranslationsFrom(__DIR__.'/path/to/translations', 'courier');
$this->publishes([
__DIR__.'/path/to/translations' => resource_path('lang/vendor/courier'),
]);
}
If you don't have translation in app's lang/vendor/courier then it falls back to your package translation.
You don't need to copy your class codes, which could remain in your package directory. The only things you copy will be your views, assets, translation files etc.
This should help you.

Related

Yii2 Console: app\models Class not found but common\models found

I have an Yii2 web application with 50+ model class files that are located in /models directory.
Now I want to run some console scripts from /console/controllers/MyController.php using these models but get class app\models\ModelName not found error, despite of use app\models\ModelName at the top.
If I copy a model file to /console/models/ModelName.php or /common/models/ModelName.php (and make change in use) it works alright. Is there any option to use models from /model or should I refactor the application so that both web and console use model files from /common/models
If you are using yii2-advanced build take in mind that #app alias is set each time depending on what part of application you are using.
If you are making a call from frontend, #app will be equal to /path/to/project-root/frontend.
If from backend - /path/to/project-root/backend.
console - /path/to/project-root/console
You may add custom alias in /common/config/bootstrap.php, to make your classes available from root.
For example try to add Yii::setAlias('#root', dirname(dirname(__DIR__))); to /common/config/bootstrap.php and set namespace to root/models
Note: if you will try add #app to bootstrap.php, it will be automatically reassigned by framework.
Note 2: You may check how yii2 autoloader works in BaseYii.php

Overriding configuration files of composer packages in Lumen

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.

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.

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;
}
}

Symfony 1.4 - Doctrine - Custom Plugin - How do I get plugin model files to reside in plugin directory?

I am creating a custom plugin, and am trying to keep all related model files contained within the plugin directory structure. However, when I build the model, some files get dropped into lib/model/doctrine/... and others in plugins/userPlugin/lib/model/... . According to Doctrine docs I can add a "package" option to the schema.yml file, and generated model files will be created in the location as defined by my dot-notation entry, for example:
# plugins/userPlugin/config/doctrine/schema.yml
connection: store-rw-user
options:
# Fully expect resulting model files to be dropped in this directory (vs the main model dir)
package: userPlugin.lib.model.doctrine
....
As mentioned, this config setup still results in model files being dropped into the main lib/model/doctrine directory. I even tried this, to no avail:
# plugins/userPlugin/config/doctrine/schema.yml
connection: store-rw-user
options:
package: userPlugin
package_custom_path: /tmp/userPlugin
....
Just wanted to see if the files were dropped in the /tmp directory, but they were not.
Before I start tearing apart the source code, I figured I would ask first, to see if there is something I am missing.
It's perfectly normal to get model files in your project directory after building. The purpose of this is to let you customize the plugin model on per-project basis, because the classes inside these files inherit from the classes defined in the plugin's files. I use plugins too, and most of the time, all the code I write resides in the plugin's model files.

Categories