webkernel/lifecycle

Writing Actions

On this page

An action owns one piece of Composer-time work, usually a generated artifact. Declare it once; the built-in post-autoload worker runs it after environment checks whenever Composer regenerates the autoloader.

1. Write the action

For Acme\Build\ mapped to src/, save this as src/GenerateManifest.php:

<?php declare(strict_types=1);

namespace Acme\Build;

use RuntimeException;
use Webkernel\Lifecycle\StandardComposerIO;
use Webkernel\Lifecycle\StandardLCAction;

final class GenerateManifest extends StandardLCAction
{
    protected function run(): void
    {
        $directory = base_path('runtime/build');

        if (! is_dir($directory)
            && ! mkdir($directory, 0775, true)
            && ! is_dir($directory)) {
            throw new RuntimeException('Unable to create the build directory.');
        }

        $output_path = $directory . '/manifest.json';
        $contents = json_encode(['format' => 1], JSON_THROW_ON_ERROR) . "\n";

        $current_contents = is_file($output_path) ? file_get_contents($output_path) : false;
        if ($current_contents === $contents) {
            StandardComposerIO::write('Build manifest is current.');
            return;
        }

        $temporary_path = tempnam($directory, '.manifest-');
        if ($temporary_path === false) {
            throw new RuntimeException('Unable to create a temporary manifest.');
        }

        try {
            if (file_put_contents($temporary_path, $contents) !== strlen($contents)
                || ! rename($temporary_path, $output_path)) {
                throw new RuntimeException('Unable to publish the build manifest.');
            }
        } finally {
            if (is_file($temporary_path)) {
                unlink($temporary_path);
            }
        }

        StandardComposerIO::write('Wrote runtime/build/manifest.json.');
    }
}

This example stores generated application state under runtime/, avoids rewriting an unchanged artifact and publishes a changed file by replacing it in the same directory. For generated PHP, invalidate the affected OPcache entry after replacement when applicable.

2. Declare it

{
  "extra": {
    "webkernel": {
      "lifecycle": {
        "actions": ["Acme\\Build\\GenerateManifest"]
      }
    }
  }
}

Run composer dump-autoload. Actions are classes, not ClassName::method targets. They must be instantiable, implement LifecycleActionContract and have no required constructor arguments. Lifecycle validates every declared action before starting the action phase.

Keys, names and context

StandardLCAction provides key(), name() and a final handle(Event $event) method. You implement protected function run(): void. Use composerEvent() inside the action if you need the Composer event.

ClassDefault keyDefault name
GenerateManifestgenerate-manifestGenerate Manifest
GenerateManifestActiongenerate-manifestGenerate Manifest

Override key() or name() for a stable identifier or custom label. The current runner executes declarations as listed; a key does not deduplicate actions or create dependency ordering. Implement LifecycleActionContract directly when the standard base does not fit.

Order and failure

Action lists retain their order within a package. The runner prioritizes an empty package name, then webkernel/codebase, then other names alphabetically. A named root package participates by name; do not assume it always runs first.

An execution exception is reported, then later actions continue. The built-in worker throws after the phase if any actions failed. A declaration-validation error stops before action execution. Successful writes are not rolled back if a later action fails.

Optional example action

Lifecycle includes Webkernel\Lifecycle\Workers\ActionExampleAction, which is disabled by default. Declaring it writes generated/lifecycle-example.txt inside the installed Lifecycle package. It demonstrates the API; the application-oriented example above writes to application runtime storage instead.

Next step

Format output with Composer Output. See Failure Semantics for phase-level behavior.