Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Installer Plugin Laravel Package

eckinox/installer-plugin

Composer plugin that installs eckinox-metapackage packages by replicating a package’s replicate/ directory into your project, merging folders and overwriting same-named files. Supports custom handler classes to control behavior for new and existing files.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Install the Plugin Add the plugin to your project’s composer.json under require-dev:

    composer require --dev eckinox/installer-plugin
    

    Ensure your composer.json includes the plugin in the extra section:

    {
        "extra": {
            "installer-paths": {
                "vendor/eckinox/installer-plugin={$name}"
            }
        }
    }
    
  2. Create a Metapackage Build a package with a replicate directory containing files/configs to deploy. Example structure:

    my-metapackage/
    ├── composer.json
    ├── replicate/
    │   ├── .env.example
    │   ├── phpunit.xml
    │   └── scripts/
    │       └── deploy.sh
    

    Define the package type in composer.json:

    {
        "name": "my-vendor/my-metapackage",
        "type": "eckinox-metapackage",
        "extra": {
            "class": "MyVendor\\MyMetapackage\\ReplicationHandler"
        }
    }
    
  3. First Use Case Require the metapackage in your Laravel project:

    composer require my-vendor/my-metapackage
    

    Verify files are replicated to your project root (e.g., .env.example appears in your Laravel project).


Implementation Patterns

Usage Patterns

  1. Basic File Replication Use the replicate directory to deploy static files (e.g., config templates, scripts):

    # Install a metapackage with pre-defined files
    composer require vendor/metapackage
    
    • Files in replicate/ are copied to the project root.
    • Directories are merged; files are overwritten if they exist.
  2. Handler-Driven Customization Extend Eckinox\Composer\HandlerInterface for dynamic logic:

    namespace MyVendor\MyMetapackage;
    
    use Eckinox\Composer\HandlerInterface;
    use Composer\Package\PackageInterface;
    use Composer\Util\Filesystem;
    use Composer\IO\IOInterface;
    
    class ReplicationHandler implements HandlerInterface
    {
        public function __construct(
            private PackageInterface $package,
            private Filesystem $filesystem,
            private IOInterface $io
        ) {}
    
        public function handleExistingFile(string $packageFilename, string $projectFilename, ?string $currentlyInstalledFilename = null)
        {
            // Logic for existing files (e.g., log conflicts)
            $this->io->writeError("File $projectFilename already exists. Skipping.");
        }
    
        public function postFileCreationCallback(string $projectFilename)
        {
            // Post-processing (e.g., chmod, rename)
            if (basename($projectFilename) === 'deploy.sh') {
                chmod($projectFilename, 0755);
            }
        }
    }
    
    • Declare the handler in composer.json under "extra": { "class": "MyVendor\\MyMetapackage\\ReplicationHandler" }.
  3. Version-Aware Updates Leverage $currentlyInstalledFilename to detect changes between versions:

    public function handleExistingFile(string $packageFilename, string $projectFilename, ?string $currentlyInstalledFilename = null)
    {
        if ($currentlyInstalledFilename && md5_file($currentlyInstalledFilename) !== md5_file($packageFilename)) {
            $this->io->write("Updated $projectFilename from version " . $this->package->getVersion());
        }
    }
    
  4. Laravel Integration Combine with Laravel’s composer.json scripts for post-install actions:

    {
        "scripts": {
            "post-install-cmd": [
                "@php artisan config:clear",
                "@php artisan cache:clear"
            ]
        }
    }
    

Workflows

  1. Project Scaffolding

    • Package: company-template-metapackage
    • replicate/ contains:
      • .env.example
      • phpunit.xml
      • webpack.mix.js
    • Workflow: New Laravel projects composer require company/template-metapackage to bootstrap.
  2. Environment-Specific Configs

    • Package: env-config-metapackage
    • replicate/ includes:
      • docker-compose.ci.yml
      • docker-compose.local.yml
    • Handler Logic: Skip replication if .env already exists (avoid overwrites).
  3. Internal Tooling

    • Package: dev-tools-metapackage
    • replicate/ contains:
      • artisan commands (e.g., php artisan generate:model)
      • Custom scripts (e.g., php scripts/lint.php)
    • Handler Logic: Validate file permissions post-install.

Integration Tips

  • Avoid Conflicts:
    • Use handlers to skip replication for critical files (e.g., .env, composer.json).
    • Example:
      public function postFileCreationCallback(string $projectFilename) {
          if (in_array(basename($projectFilename), ['.env', 'composer.json'])) {
              unlink($projectFilename);
              $this->io->writeError("Skipped replication of $projectFilename to avoid conflicts.");
          }
      }
      
  • Leverage Composer Events:
    • Trigger Laravel actions via composer.json scripts:
      {
          "scripts": {
              "post-update-cmd": [
                  "@php artisan config:publish",
                  "@php artisan view:clear"
              ]
          }
      }
      
  • Test Handlers:
    • Mock Filesystem and IOInterface in PHPUnit:
      $handler = new MyHandler($package, $mockFilesystem, $mockIO);
      $handler->postFileCreationCallback('/path/to/file');
      $this->assertFileExists('/path/to/file');
      

Gotchas and Tips

Pitfalls

  1. File Overwrite Behavior

    • Issue: Files in replicate/ overwrite existing files in the project root.
    • Fix: Use handleExistingFile() to log or skip conflicts:
      public function handleExistingFile(string $packageFilename, string $projectFilename, ?string $currentlyInstalledFilename = null) {
          $this->io->writeError("Conflict: $projectFilename exists. Use --force to overwrite.");
      }
      
    • Laravel Risk: Replicating config/app.php or routes/web.php can break functionality.
  2. Permission Issues

    • Issue: Replicated files may inherit incorrect permissions (e.g., storage/ needs 775).
    • Fix: Set permissions in postFileCreationCallback:
      public function postFileCreationCallback(string $projectFilename) {
          if (str_contains($projectFilename, 'storage/')) {
              chmod($projectFilename, 0775);
          }
      }
      
    • Test: Verify on shared hosting (e.g., safe_mode environments).
  3. Handler Autoloading

    • Issue: Handlers must be autoloaded or Composer will fail silently.
    • Fix: Ensure composer.json includes:
      {
          "autoload": {
              "psr-4": {
                  "MyVendor\\MyMetapackage\\": "src/"
              }
          }
      }
      
    • Debug: Check composer dump-autoload after adding handlers.
  4. Path Handling Across OS

    • Issue: Windows/Linux path separators (\ vs /) can break handlers.
    • Fix: Normalize paths:
      $projectFilename = str_replace('\\', '/', $projectFilename);
      
    • Test: Use DIRECTORY_SEPARATOR for cross-platform compatibility.
  5. Partial Installs

    • Issue: If the handler fails to load, Composer falls back to partial installation (v1.2.2), which may leave files in an inconsistent state.
    • Fix: Validate handler classes in CI:
      composer validate --strict
      
  6. Laravel Cache Invalidation

    • Issue: Replicating config/ files won’t trigger Laravel’s cache clearing.
    • Fix: Add a composer.json script:
      {
          "scripts": {
              "post-install-cmd": [
                  "@php artisan config:clear"
              ]
          }
      }
      

Debugging

  1. Enable Composer Debug Mode Run Composer with -vvv to debug plugin execution:

    composer install -vvv
    
    • Look for Eckinox\Composer\Plugin logs.
  2. Handler Debugging Use IOInterface to log handler execution:

    public function postFileCreationCallback(string $projectFilename) {
        $this->io->write("Replicating: $projectFilename");
        // Your logic here
    }
    
  3. Check Partial Installs If

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor