> ## Documentation Index
> Fetch the complete documentation index at: https://suvera.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# The Module System: Extending Winter with Libraries

> Understand the WinterModule contract and #[Module] attribute that every Winter library uses to register beans, scan namespaces, and boot infrastructure.

Winter Boot's module system gives you a clean, attribute-driven mechanism for bundling infrastructure integrations — Redis, Kafka, Doctrine ORM, service discovery, and more — as self-contained, reusable units. Modules are discovered and loaded before the application starts, so each module can register its own beans, scan additional namespaces, and run any required initialisation without touching your application code. The `WinterModule` interface keeps the contract minimal: implement two lifecycle hooks and annotate your class with `#[Module]`.

## The `WinterModule` Interface

Every module must implement the `WinterModule` interface. The framework calls its two lifecycle methods during startup in a predictable order.

```php theme={null}
use dev\winterframework\core\app\WinterModule;
use dev\winterframework\core\context\ApplicationContext;
use dev\winterframework\core\context\ApplicationContextData;

class MyCustomModule implements WinterModule {

    /**
     * Called during the module loading phase.
     * Register beans, validate configuration, check required extensions here.
     */
    public function init(ApplicationContext $ctx, ApplicationContextData $ctxData): void {
        // initialise resources
    }

    /**
     * Called after all modules are loaded and the application context is ready.
     * Start background processes, connect to external services, etc.
     */
    public function begin(ApplicationContext $ctx, ApplicationContextData $ctxData): void {
        // begin operations
    }
}
```

<ParamField body="init()" type="void">
  Called during the **module loading** phase. Use this hook to register beans, validate configuration, and verify required PHP extensions are present.
</ParamField>

<ParamField body="begin()" type="void">
  Called after **all modules are loaded** and the application context is fully ready. Use this hook to open connections, start background processes, or subscribe to events.
</ParamField>

## The `#[Module]` Attribute

Annotate every module class with `#[Module]`. This tells the framework how to scan the module's namespaces and provides metadata used in log output.

```php theme={null}
use dev\winterframework\stereotype\Module;

#[Module(
    title: 'My Custom Module',      // human-readable name shown in logs
    initMethod: 'init',             // method called on load (default: 'init')
    destroyMethod: '',              // method called on shutdown (optional)
    namespaces: [],                 // extra PSR-4 namespaces to scan
)]
class MyCustomModule implements WinterModule {
    // ...
}
```

<Note>
  When `namespaces` is left empty, the framework automatically registers the namespace derived from the module file's location. Only provide explicit `[namespace, directory]` pairs when your module ships classes in directories outside its own file path.
</Note>

## Enabling Modules in `application.yml`

Declare modules in your `application.yml` under the top-level `modules` key. Each entry requires a `module` class name and an `enabled` flag.

```yaml application.yml theme={null}
modules:
  - module: 'dev\winterframework\telemetry\OpenTelemetryModule'
    enabled: true
    configFile: 'config/telemetry.yml'   # optional path to module-specific config

  - module: 'dev\winterframework\data\redis\RedisModule'
    enabled: true

  - module: 'dev\winterframework\kafka\KafkaModule'
    enabled: false   # set to false to temporarily disable
```

<Warning>
  Modules are loaded in the order they appear in `application.yml`. If one module depends on beans registered by another, place the dependency first in the list.
</Warning>

## First-Party Modules

All official modules live in the `suvera/winter-modules` monorepo. Install the entire collection with a single Composer command:

```bash theme={null}
composer require suvera/winter-modules
```

See the [Modules overview](/modules/overview) for a full catalog with guidance on which module to pick for which use case.

<CardGroup cols={2}>
  <Card title="Doctrine" icon="table" href="/modules/doctrine">
    Doctrine ORM and DBAL for entity management, DBAL, and multi-tenant datasources.
  </Card>

  <Card title="Redis" icon="database" href="/modules/data-redis">
    PhpRedis client templates for singles, clusters, arrays, sentinels, and token rings.
  </Card>

  <Card title="Memcache" icon="memory" href="/modules/data-memcache">
    Memcached and Memcache client templates for lightweight caching.
  </Card>

  <Card title="Kafka" icon="signal" href="/modules/kafka">
    Apache Kafka producer and consumer integration for event streaming pipelines.
  </Card>

  <Card title="SQS" icon="envelope" href="/modules/sqs">
    Amazon SQS producer and consumer with IAM role and IRSA support.
  </Card>

  <Card title="S3" icon="cloud" href="/modules/s3">
    Amazon S3 and S3-compatible object storage from any bean.
  </Card>

  <Card title="OpenSearch" icon="magnifying-glass" href="/modules/opensearch">
    OpenSearch indexing, querying, and AWS SigV4-signed access.
  </Card>

  <Card title="DTCE" icon="rotate" href="/modules/dtce">
    Distributed Task Computing Engine for cross-node background task orchestration.
  </Card>

  <Card title="Eureka" icon="network-wired" href="/modules/eureka">
    Service discovery via Consul and Netflix Eureka.
  </Card>

  <Card title="Memdb" icon="hard-drive" href="/modules/memdb">
    Embedded in-memory servers (Redis, Ignite, Memcached, Hazelcast) managed by the app lifecycle. *EXPERIMENTAL*
  </Card>

  <Card title="Security" icon="shield" href="/modules/security">
    Application security policies for Winter Boot applications.
  </Card>
</CardGroup>

## Building a Custom Module

Package any infrastructure concern — a third-party SDK, a custom cache layer, an internal service client — as a reusable, injectable module by following these steps.

<Steps>
  <Step title="Create the module class">
    ```php src/Module/AcmeMyModule.php theme={null}
    <?php
    declare(strict_types=1);

    namespace Acme\MyModule;

    use dev\winterframework\core\app\WinterModule;
    use dev\winterframework\core\context\ApplicationContext;
    use dev\winterframework\core\context\ApplicationContextData;
    use dev\winterframework\stereotype\Module;

    #[Module(title: 'Acme My Module')]
    class AcmeMyModule implements WinterModule {

        public function init(ApplicationContext $ctx, ApplicationContextData $ctxData): void {
            // Validate required config, register beans
        }

        public function begin(ApplicationContext $ctx, ApplicationContextData $ctxData): void {
            // Start connections or background processes
        }
    }
    ```
  </Step>

  <Step title="Register beans inside init()">
    Use `ApplicationContextData::getBeanProvider()` to register beans that consumers can inject with `#[Autowired]`:

    ```php theme={null}
    public function init(ApplicationContext $ctx, ApplicationContextData $ctxData): void {
        $client = new AcmeClient(/* config */);

        $ctxData->getBeanProvider()->registerInternalBean(
            $client,
            AcmeClient::class,
            true          // mark as primary bean
        );
    }
    ```
  </Step>

  <Step title="Read module configuration">
    The framework passes the raw `moduleDef` YAML entry to your `#[Module]` attribute. Use the `ModuleTrait` helper to retrieve it:

    ```php theme={null}
    use dev\winterframework\util\ModuleTrait;

    #[Module(title: 'Acme My Module')]
    class AcmeMyModule implements WinterModule {
        use ModuleTrait;

        public function begin(ApplicationContext $ctx, ApplicationContextData $ctxData): void {
            $moduleDef = $ctx->getModule(static::class);
            $config    = $this->retrieveConfiguration($ctx, $ctxData, $moduleDef);

            $host = $config['acme']['host'] ?? 'localhost';
        }
    }
    ```
  </Step>

  <Step title="Enable the module in application.yml">
    ```yaml application.yml theme={null}
    modules:
      - module: 'Acme\MyModule\AcmeMyModule'
        enabled: true
        configFile: 'config/acme.yml'
    ```
  </Step>

  <Step title="Install via Composer">
    ```bash theme={null}
    composer require acme/my-winter-module
    ```
  </Step>
</Steps>

<Tip>
  See the `suvera/winter-modules` repository for real-world examples of how first-party modules are structured and tested — it is the best reference when building your own.
</Tip>
