search

Home  >  Q&A  >  body text

How to uninstall autoloading in custom installer plugin

<p>I've been trying to write a custom installer for my Composer package but can't get it to work. What I need now is:</p><p><ul><li>I want my package to be installed in the root directory. My package name is rootdata21/hati, so I moved the hati folder to the root of the project. </li><li>Now I updated it by adding an entry to the autoload psr4 attribute of the composer.json file as follows: { "autoload": { "psr-4": { "hati" : "hati/" } } }</li></ul></p><p>But I don't actually know how to get composer to regenerate the autoloader to reflect the ones in the composer.json file This new autoload entry. Below is my Installer class.</p><p><br /></p> <pre class="brush:php;toolbar:false;"><?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); } }</pre> <p><br /></p>
P粉466909449P粉466909449515 days ago459

reply all(1)I'll reply

  • P粉068510991

    P粉0685109912023-08-01 09:38:32

    I have successfully achieved what I wanted to do. So here I'll explain the help I'm looking for.

    Normally, if I do not use any custom installation plug-in, Composer will install my package in the vendor directory named "rootdata21/hati". But for some reason my entire package source code needs to be in the project root. And I don't want to have a parent folder named rootdata21 either.

    So I wrote a plugin for this. The plugin returns "rootdata21" as the installation path. It puts my package in the root directory, but the folder structure now becomes "rootdata21/hati". Therefore, I had to override the installation method to modify it. However, even if I get the folder location and structure I want by copying/renaming/deleting the folders from "rootdata21/hati", the autoloader still doesn't work with my relocated source code. I then had to manually update the composer.json file to regenerate the autoloader, which defeats the purpose of having an installer. This is what I want to achieve, is that after moving my package folder to the project root, the autoloader still works properly.

    This is my final updated installer code that works the way I want it to.


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

    After all these operations, the vendor/composer/autoload_psr4.php file has the classpath correctly set, as you can see in the screenshot.

    I had to return "hati" as the installation path because if I returned "rootdata21" and used the installation code above, I would get the following autoload_psr4.php record, which does not work properly.


    'hati\' => array($baseDir . '/rootdata') 

    reply
    0
  • Cancelreply