我一直在尝试为我的Composer包编写自定义安装程序,但无法使其工作。我现在需要的是:
但是我实际上不知道如何让composer重新生成自动加载器,以反映composer.json文件中的这个新的autoload条目。以下是我的Installer类。
<?php
namespace hatiinstaller;
use ComposerInstallerLibraryInstaller;
use ComposerIOIOInterface;
use ComposerPackagePackageInterface;
use ComposerPartialComposer;
use ComposerRepositoryInstalledRepositoryInterface;
use ComposerScriptScriptEvents;
use haticonfigConfigWriter;
use ReactPromisePromiseInterface;
class Installer extends LibraryInstaller {
private string $root;
private string $hatiDir;
protected $composer;
public function __construct(IOInterface $io, PartialComposer $composer, $root) {
$this -> composer = $composer;
$this -> root = $root . DIRECTORY_SEPARATOR;
$this -> hatiDir = $root . DIRECTORY_SEPARATOR . 'hati' . DIRECTORY_SEPARATOR;
parent::__construct($io, $composer);
}
public function getInstallPath(PackageInterface $package): string {
return 'rootdata21';
}
public function install(InstalledRepositoryInterface $repo, PackageInterface $package): ?PromiseInterface {
if (file_exists($this -> hatiDir)) {
$choice = $this -> io -> ask('Existing hati folder found. Do you want to delete it? [y/n]: ', 'n');
if ($choice === 'y') {
self::rmdir($this -> hatiDir);
} else {
$this -> io -> critical('Hati installation has been cancelled. Please delete hati folder manually.');
return null;
}
}
return parent::install($repo, $package)->then(function () {
// Move hati folder to project root directory
$old = $this -> root . 'rootdata21'. DIRECTORY_SEPARATOR .'hati';
rename($old, $this -> hatiDir);
// delete the rootdata21 folder
self::rmdir($this -> root . 'rootdata21');
// generate/update the hati.json file on the project root directory
$createNewConfig = true;
if (file_exists($this -> root . 'hati.json')) {
while(true) {
$ans = $this -> io -> ask('Existing hati.json found. Do you want to merge it with new config? [y/n]: ');
if ($ans !== 'y' && $ans !== 'n') continue;
break;
}
$createNewConfig = $ans == 'n';
}
require_once "{$this -> hatiDir}config" . DIRECTORY_SEPARATOR . "ConfigWriter.php";
$result = ConfigWriter::write($this->root, $createNewConfig);
// show the result to the user
if ($result['success']) {
$this -> io -> info($result['msg']);
$welcomeFile = $this -> hatiDir . 'page/welcome.txt';
if (file_exists($welcomeFile)) include($welcomeFile);
} else {
$this -> io -> error($result['msg']);
}
$this -> dumpAutoload();
});
}
public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target) {
return parent::update($repo, $initial, $target) -> then(function () {
require_once "{$this -> hatiDir}config" . DIRECTORY_SEPARATOR . "ConfigWriter.php";
$result = ConfigWriter::write($this->root);
// show the result to the user
if ($result['success']) {
$this -> io -> info('Hati has been updated successfully');
} else {
$this -> io -> error($result['msg']);
}
});
}
public function supports($packageType): bool {
return 'hati-installer' === $packageType;
}
private function dumpAutoload(): void {
$composerJsonPath = $this -> root . 'composer.json';
$composerJson = json_decode(file_get_contents($composerJsonPath), true);
$composerJson['autoload']['psr-4']['hati\'] = 'hati/';
file_put_contents($composerJsonPath, json_encode($composerJson, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
// Regenerate the Composer autoload files to include your classes
$this -> composer -> getEventDispatcher() -> dispatchScript(ScriptEvents::POST_AUTOLOAD_DUMP);
}
public static function rmdir($dir): bool {
if (!file_exists($dir)) return true;
if (!is_dir($dir)) return unlink($dir);
foreach (scandir($dir) as $item) {
if ($item == '.' || $item == '..') continue;
if (!self::rmdir($dir . DIRECTORY_SEPARATOR . $item)) return false;
}
return rmdir($dir);
}
}
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号
我已经成功实现了我想要做的事情。所以在这里,我将解释我所寻求的帮助。
通常情况下,如果不使用任何自定义的安装插件,Composer会将我的包安装在名为"rootdata21/hati"的vendor目录下。但由于某些原因,我的整个包源代码需要位于项目根目录下。而且我也不希望有名为rootdata21的父文件夹。
因此,我为此编写了一个插件。该插件将"rootdata21"作为安装路径返回。它将我的包放在了根目录下,但是文件夹结构现在变成了"rootdata21/hati"。因此,我不得不重写安装方法来修改它。然而,即使我通过从"rootdata21/hati"复制/重命名/删除文件夹来获得我想要的文件夹位置和结构,自动加载器对我重新定位的源代码仍然无效。然后,我不得不手动更新composer.json文件来重新生成自动加载器,这与拥有安装程序的目的相悖。这就是我想要实现的,即在将我的包文件夹移动到项目根目录后,自动加载器仍然能够正常工作。
这是我最终更新的安装程序代码,它按照我想要的方式工作。
public function getInstallPath(PackageInterface $package): string { return 'hati'; }public function install(InstalledRepositoryInterface $repo, PackageInterface $package): ?PromiseInterface { // Setting custom psr-4 entry for hati folder being on project root $autoload = $package -> getAutoload(); if (isset($autoload['psr-4'])) { $customPSR4 = ['hati\\' => '/',]; $autoload['psr-4'] = array_merge($autoload['psr-4'], $customPSR4); // Let the composer know about this $package -> setAutoload($autoload); } return parent::install($repo, $package) -> then(function () { // Manipulate the hati/hati folder to hati on project root self::copy($this -> root . 'hati' . DIRECTORY_SEPARATOR . 'hati', $this -> root . '_temp'); self::rmdir($this -> root . 'hati'); rename($this -> root . '_temp',$this -> root . 'hati'); // rest of the installation code goes here... }); }在所有这些操作之后,vendor/composer/autoload_psr4.php文件正确地设置了类路径,您可以在截图中看到。
我不得不将"hati"作为安装路径返回,因为如果返回"rootdata21"并使用上面的安装代码,将会得到以下的autoload_psr4.php记录,而这并不能正常工作。
'hati\\' => array($baseDir . '/rootdata')