-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
686950e
commit 1d7e39a
Showing
3 changed files
with
299 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,103 @@ | ||
# Autoload Your Files Before Vendor Files | ||
# Composer Preload Files Plugin | ||
|
||
[![GitHub release](https://img.shields.io/github/release/codezero-be/composer-preload-files.svg?style=flat-square)](https://github.com/codezero-be/composer-preload-files/releases) | ||
[![License](https://img.shields.io/packagist/l/codezero/composer-preload-files.svg?style=flat-square)](LICENSE.md) | ||
[![Total Downloads](https://img.shields.io/packagist/dt/codezero/composer-preload-files.svg?style=flat-square)](https://packagist.org/packages/codezero/composer-preload-files) | ||
|
||
## Autoload Your Files Before Vendor Files | ||
|
||
This Composer plugin enables you to autoload files that you specify before any vendor files. | ||
|
||
This package is based on the original [funkjedi/composer-include-files](https://github.com/funkjedi/composer-include-files) by [@funkjedi](https://github.com/funkjedi) and its fork [hopeseekr-contribs/composer-include-files](https://github.com/hopeseekr-contribs/composer-include-files) by [@hopeseekr](https://github.com/hopeseekr). | ||
Because maintenance of these packages appears to be stalled, I decided to attempt and remake the package from scratch and fix any reported bugs in the process. | ||
|
||
## ✅ Requirements | ||
|
||
- PHP >= 7.0 | ||
- Composer ^2.0 | ||
|
||
## 📦 Install | ||
|
||
Install this package with Composer: | ||
|
||
```bash | ||
composer require codezero/composer-preload-files | ||
``` | ||
|
||
## 📘 Usage | ||
|
||
Add the `preload-files` to your project's `composer.json` under the `extra` section: | ||
|
||
```json | ||
"extra": { | ||
"preload-files": [ | ||
"app/helpers.php" | ||
] | ||
}, | ||
``` | ||
|
||
The `preload-files` in the `extra` section will be loaded before the `files` in a standard `autoload` or `autoload-dev` section. | ||
This is true for your project, but also for any vendor package. Your project's preload files will always be loaded first. | ||
|
||
## 🔌 Example Use Case | ||
|
||
The best example use case is when you need to override a global helper function in a [Laravel](https://laravel.com) project. | ||
Those helper functions are declared in helper files that are loaded in the `files` array in the `autoload` section of `composer.json`: | ||
|
||
```json | ||
"autoload": { | ||
"files": [ | ||
"src/Illuminate/Collections/helpers.php", | ||
"src/Illuminate/Events/functions.php", | ||
"src/Illuminate/Foundation/helpers.php", | ||
"src/Illuminate/Support/helpers.php" | ||
] | ||
}, | ||
``` | ||
|
||
These functions are declared like this: | ||
|
||
```php | ||
// helpers.php | ||
if ( ! function_exists('route')) { | ||
function route($name, $parameters = [], $absolute = true) | ||
{ | ||
return app('url')->route($name, $parameters, $absolute); | ||
} | ||
} | ||
``` | ||
|
||
If you add your own helper file to your project's `autoload` section to override such function, you will notice that Laravel's function is already loaded, and you can not redeclare it. | ||
|
||
One way to solve this, is to manually `require` the helper file before Composer's `autoload.php` file. | ||
For Laravel, this means you need to `require` the file in your project's `public/index.php` file: | ||
|
||
```php | ||
require __DIR__.'/../app/helpers.php'; | ||
require __DIR__.'/../vendor/autoload.php'; | ||
``` | ||
|
||
This works, but it is difficult, if not impossible to test (I did not find a way yet). | ||
If you are developing a package, it's also an extra step that users need take to install it. | ||
|
||
Another solution is a package like this. | ||
|
||
## ☕ Credits | ||
|
||
- [@ivanvermeyen](https://github.com/ivanvermeyen) | ||
- [@hopeseekr](https://github.com/hopeseekr) - original fork: [hopeseekr-contribs/composer-include-files](https://github.com/hopeseekr-contribs/composer-include-files) | ||
- [@funkjedi](https://github.com/funkjedi) - original: [funkjedi/composer-include-files](https://github.com/funkjedi/composer-include-files) | ||
- [All contributors](https://github.com/codezero-be/composer-preload-files/contributors) | ||
|
||
## 🔒 Security | ||
|
||
If you discover any security related issues, please [e-mail me](mailto:ivan@codezero.be) instead of using the issue tracker. | ||
|
||
## 📑 Changelog | ||
|
||
A complete list of all notable changes to this package can be found on the | ||
[releases page](https://github.com/codezero-be/composer-preload-files/releases). | ||
|
||
## 📜 License | ||
|
||
The MIT License (MIT). Please see [License File](LICENSE.md) for more information. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
<?php | ||
|
||
namespace CodeZero\ComposerPreloadFiles; | ||
|
||
use Composer\Autoload\AutoloadGenerator as ComposerAutoloadGenerator; | ||
use Composer\Composer; | ||
use Composer\IO\IOInterface; | ||
use Composer\Package\CompletePackage; | ||
use Composer\Pcre\Preg; | ||
use Composer\Util\Filesystem; | ||
use Composer\Util\Platform; | ||
|
||
class AutoloadGenerator extends ComposerAutoloadGenerator | ||
{ | ||
/** | ||
* Add preload files to the autoload files. | ||
* | ||
* @param \Composer\Composer $composer | ||
* @param \Composer\IO\IOInterface $io | ||
* @param \Composer\Util\Filesystem $filesystem | ||
* | ||
* @return void | ||
*/ | ||
public function addPreloadFilesToAutoloadFiles(Composer $composer, IOInterface $io, Filesystem $filesystem) | ||
{ | ||
$preloadFiles = $this->parsePreloadFiles($composer, $filesystem); | ||
|
||
if (count($preloadFiles) === 0) { | ||
return; | ||
} | ||
|
||
$io->writeError('<info>Adding preload files to the autoload files.</info>'); | ||
|
||
// Some pathfinding... | ||
// Do not remove double realpath() calls. | ||
// Fixes failing Windows realpath() implementation. | ||
// See https://bugs.php.net/bug.php?id=72738 | ||
$basePath = $filesystem->normalizePath(realpath(realpath(Platform::getCwd()))); | ||
$vendorDir = $composer->getConfig()->get('vendor-dir'); | ||
$vendorPath = $filesystem->normalizePath(realpath(realpath($vendorDir))); | ||
$targetDir = $vendorPath.'/composer'; | ||
|
||
$this->prependPreloadFilesToAutoloadFilesFile($filesystem, $preloadFiles, $targetDir, $basePath, $vendorPath); | ||
$this->regenerateAutoloadStaticFile($filesystem, $targetDir, $basePath, $vendorPath); | ||
} | ||
|
||
/** | ||
* Prepend preload files to the 'autoload_files.php' file. | ||
* | ||
* @param \Composer\Util\Filesystem $filesystem | ||
* @param array $preloadFiles | ||
* @param string $targetDir | ||
* @param string $basePath | ||
* @param string $vendorPath | ||
* | ||
* @return void | ||
*/ | ||
protected function prependPreloadFilesToAutoloadFilesFile(Filesystem $filesystem, $preloadFiles, $targetDir, $basePath, $vendorPath) | ||
{ | ||
$vendorPathCode = $filesystem->findShortestPathCode(realpath($targetDir), $vendorPath, true); | ||
$appBaseDirCode = $filesystem->findShortestPathCode($vendorPath, $basePath, true); | ||
$appBaseDirCode = str_replace('__DIR__', '$vendorDir', $appBaseDirCode); | ||
$autoloadFilesFilePath = $targetDir.'/autoload_files.php'; | ||
|
||
// Merge preload files with original files. | ||
$originalFiles = $this->getOriginalAutoloadFiles($autoloadFilesFilePath); | ||
$allFiles = array_merge($preloadFiles, $originalFiles); | ||
|
||
// Write new 'autoload_files.php'. | ||
$filesystem->filePutContentsIfModified( | ||
$autoloadFilesFilePath, | ||
$this->getIncludeFilesFile($allFiles, $filesystem, $basePath, $vendorPath, $vendorPathCode, $appBaseDirCode) | ||
); | ||
} | ||
|
||
/** | ||
* Regenerate the 'autoload_static.php' file. | ||
* | ||
* @param \Composer\Util\Filesystem $filesystem | ||
* @param string $targetDir | ||
* @param string $basePath | ||
* @param string $vendorPath | ||
* | ||
* @return void | ||
*/ | ||
protected function regenerateAutoloadStaticFile(Filesystem $filesystem, $targetDir, $basePath, $vendorPath) | ||
{ | ||
// Get the class name suffix from 'autoload.php'. | ||
// https://github.com/composer/composer/blob/main/src/Composer/Autoload/AutoloadGenerator.php#L390-L392 | ||
$autoloadContent = file_get_contents($vendorPath.'/autoload.php'); | ||
$suffix = null; | ||
if (Preg::isMatch('{ComposerAutoloaderInit([^:\s]+)::}', $autoloadContent, $match)) { | ||
$suffix = $match[1]; | ||
} | ||
|
||
// Write new 'autoload_static.php'. | ||
$filesystem->filePutContentsIfModified( | ||
$targetDir.'/autoload_static.php', | ||
$this->getStaticFile($suffix, $targetDir, $vendorPath, $basePath) | ||
); | ||
} | ||
|
||
/** | ||
* Get the original files to autoload. | ||
* | ||
* @param string $autoloadFilesFilePath | ||
* | ||
* @return array | ||
*/ | ||
protected function getOriginalAutoloadFiles($autoloadFilesFilePath) | ||
{ | ||
if (file_exists($autoloadFilesFilePath)) { | ||
return include $autoloadFilesFilePath; | ||
} | ||
|
||
return []; | ||
} | ||
|
||
/** | ||
* Parse preload files from the root package and all vendor packages. | ||
* | ||
* @param \Composer\Composer $composer | ||
* @param \Composer\Util\Filesystem $filesystem | ||
* | ||
* @return array | ||
*/ | ||
protected function parsePreloadFiles(Composer $composer, Filesystem $filesystem) | ||
{ | ||
$installationManager = $composer->getInstallationManager(); | ||
$preloadFilesKey = 'preload-files'; | ||
$preloadFiles = []; | ||
|
||
// Do not remove double realpath() calls. | ||
// Fixes failing Windows realpath() implementation. | ||
// See https://bugs.php.net/bug.php?id=72738 | ||
$basePath = $filesystem->normalizePath(realpath(realpath(Platform::getCwd()))); | ||
|
||
$rootPackage = $composer->getPackage(); | ||
$rootPackageConfig = $rootPackage->getExtra(); | ||
$rootPackagePreloadFiles = $rootPackageConfig[$preloadFilesKey] ?? []; | ||
|
||
foreach ($rootPackagePreloadFiles as $file) { | ||
$identifier = $this->getFileIdentifier($rootPackage, $file); | ||
$preloadFiles[$identifier] = $filesystem->normalizePath($basePath . '/' . $file); | ||
} | ||
|
||
$otherPackages = $composer->getRepositoryManager()->getLocalRepository()->getCanonicalPackages(); | ||
|
||
foreach ($otherPackages as $package) { | ||
if ( ! ($package instanceof CompletePackage)) { | ||
continue; | ||
} | ||
|
||
$packageBaseDir = $filesystem->normalizePath($installationManager->getInstallPath($package)); | ||
$packageConfig = $package->getExtra(); | ||
$packagePreloadFiles = $packageConfig[$preloadFilesKey] ?? []; | ||
|
||
foreach ($packagePreloadFiles as $file) { | ||
$identifier = $this->getFileIdentifier($package, $file); | ||
$preloadFiles[$identifier] = $filesystem->normalizePath($packageBaseDir . '/' . $file); | ||
} | ||
} | ||
|
||
return $preloadFiles; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters