# Provider

The Provider handles **cross-module dependencies**. When your module needs something from another module, the Provider is where you wire that connection, always through the other module's [Facade](https://gacela-project.com/docs/1.x/facade.md).

::: tip Factory vs Provider
- **Factory** → creates objects *inside* your module (intra-module)
- **Provider** → brings in dependencies *from other modules* (inter-module)
:::

::: warning register() is final
Since 1.17.0, `AbstractProvider::register()` is `final`. Overriding it used to silently disable `#[Provides]` attribute scanning. Register services by overriding `provideModuleDependencies()` (or using `#[Provides]`) instead.
:::

## Setting a provided dependency

```php
<?php # src/Sales/SalesProvider.php

use Gacela\Framework\AbstractProvider;

final class SalesProvider extends AbstractProvider
{
    public const FACADE_COMMENT = 'FACADE_COMMENT';

    public function provideModuleDependencies(Container $container): void
    {
        $this->addCommentFacade($container);
    }

    private function addCommentFacade(Container $container): void
    {
        $container->set(
            self::FACADE_COMMENT,
            function (Container $container) {
                return $container->getLocator()->get(CommentFacade::class);
            }
        );
    }
}
```

## Factory using a provided dependency

```php
<?php # src/Sales/SalesFactory.php

use Gacela\Framework\AbstractFactory;

/**
 * @method SalesConfig getConfig()
 */
final class SalesFactory extends AbstractFactory
{
    public function createOrderCommentSaver(): OrderCommentSaver
    {
        return new OrderCommentSaver(
            $this->getCommentFacade()
        );
    }

    private function getCommentFacade(): CommentFacade
    {
        return $this->getProvidedDependency(
            SalesProvider::FACADE_COMMENT
        );
    }
}
```

## Putting it together

The Facade calls the Factory, which pulls the provided dependency, completing the chain **Facade → Factory → Provider**:

```php
<?php # src/Sales/SalesFacade.php

namespace App\Sales;

use Gacela\Framework\AbstractFacade;

/**
 * @method SalesFactory getFactory()
 */
final class SalesFacade extends AbstractFacade
{
    public function saveComment(Comment $comment): int
    {
        return $this->getFactory()
            ->createOrderCommentSaver()
            ->save($comment);
    }
}
```

## `#[Provides]` attribute

Replace stringly-typed `$container->set(KEY, fn () => ...)` boilerplate with a declarative method-level attribute.

Instead of overriding `provideModuleDependencies()`, annotate methods with `#[Provides('ID')]`. Each method is wrapped in a lazy closure and auto-injected with `Container` when declared in the signature.

```php
<?php # src/Sales/SalesProvider.php

use Gacela\Framework\AbstractProvider;
use Gacela\Framework\Attribute\Provides;
use Gacela\Framework\Container\Container;

final class SalesProvider extends AbstractProvider
{
    #[Provides('COMMANDS')]
    public function commands(): array
    {
        return [new SyncCommand()];
    }

    #[Provides('FACADE_COMMENT')]
    public function commentFacade(Container $container): CommentFacade
    {
        return $container->getLocator()->get(CommentFacade::class);
    }
}
```

With `#[Provides]`, `provideModuleDependencies()` becomes non-abstract. Providers can go attribute-only or mix both styles.

### Mixing with `provideModuleDependencies()`

You can use attributes alongside the traditional method. Attribute-registered services are resolved first, then `provideModuleDependencies()` runs as before:

```php
final class SalesProvider extends AbstractProvider
{
    #[Provides('COMMANDS')]
    public function commands(): array
    {
        return [new SyncCommand()];
    }

    public function provideModuleDependencies(Container $container): void
    {
        $container->set('LEGACY_SERVICE', fn () => new LegacyAdapter());
    }
}
```
