# Getting dependencies

Choose wiring only after the caller and service reveal a dependency. Start with the relationship: **who needs what, and who owns it?** Gacela has several resolution tools because those relationships need different boundaries.

Ask these questions in order:

1. Is the dependency created inside this module? Use the Factory.
2. Is it owned by another module? Request that module's Facade through the Provider.
3. Is it an application-wide implementation policy? Add a binding.
4. Is the caller created by another framework? Use constructor injection or Service Map at that entry point.

Then use this table as the concise decision guide.

| Intent | Recommended path |
|---|---|
| Reach another module | From an entry point, `ServiceResolverAwareTrait` + `#[ServiceMap]`; from a Factory, expose the other module's Facade through the Provider |
| Build a collaborator inside the same module | A `create*()` Factory method, or `AbstractFactory::make()` for pure autowiring |
| Obtain infrastructure | `#[Provides]` in the Provider, or app-wide `addBinding()` for an interface |
| Collect several implementations | `tag()` for an unkeyed iterable; `addHandlerRegistry()` for keyed lookup |
| Read application configuration | Typed getters on the module Config |

## Reach another module

An entry-point class such as a controller or command declares the target Facade with `#[ServiceMap]` and supplies the magic accessor with `ServiceResolverAwareTrait`:

```php
use Gacela\Framework\ServiceResolver\ServiceMap;
use Gacela\Framework\ServiceResolverAwareTrait;

#[ServiceMap(method: 'getFacade', className: BillingFacade::class)]
final class SendInvoiceController
{
    use ServiceResolverAwareTrait;

    public function __invoke(): void
    {
        $this->getFacade()->sendInvoice();
    }
}
```

Inside a Factory, go through the module's Provider instead. Factories must not call another module's Facade directly:

```php
final class InvoiceProvider extends AbstractProvider
{
    #[Provides(BillingFacade::class)]
    public function billingFacade(Container $container): BillingFacade
    {
        return $container->getLocator()->get(BillingFacade::class);
    }
}

final class InvoiceFactory extends AbstractFactory
{
    public function createSender(): InvoiceSender
    {
        return new InvoiceSender(
            $this->getProvidedDependency(BillingFacade::class),
        );
    }
}
```

Cross-module access always targets the other module's Facade, never its Factory or internal services.

## Build inside the same module

Use an explicit Factory method when construction includes decisions:

```php
public function createInvoiceSender(): InvoiceSender
{
    return new InvoiceSender($this->createPdfRenderer());
}
```

When wiring is entirely type-driven, let the module container autowire it:

```php
public function createInvoiceSender(): InvoiceSender
{
    return $this->make(InvoiceSender::class);
}
```

`make()` honors bindings, contextual bindings, `#[Inject]`, `#[Singleton]`, `#[Factory]`, and `#[Lazy]`. Runtime overrides can be passed by constructor parameter name: `$this->make(Service::class, ['currency' => 'EUR'])`.

## Obtain infrastructure

Declare a module-local dependency in its Provider:

```php
final class PaymentProvider extends AbstractProvider
{
    #[Provides(PaymentGateway::class)]
    public function paymentGateway(): PaymentGateway
    {
        return new StripeGateway();
    }
}
```

Read it in the Factory with the class-string form, which static analysis can type:

```php
$gateway = $this->getProvidedDependency(PaymentGateway::class);
```

For an interface-to-implementation rule that applies across the application, configure a binding in `gacela.php`:

```php
$config->addBinding(PaymentGateway::class, StripeGateway::class);
```

## Collect implementations

Use tags when a consumer iterates every member:

```php
$config->tag(
    [NotEmptyValidator::class, EmailValidator::class],
    'validators',
);
```

Resolve the group in a Provider with `$container->tagged('validators')`. An app-wide tag reaches every module scope; a tag added from one module's Provider stays local to that module.

Use `addHandlerRegistry()` when the consumer selects one handler by key:

```php
$config->addHandlerRegistry(HandlerRegistry::class, [
    'email' => EmailHandler::class,
    'sms' => SmsHandler::class,
]);
```

A registry answers “which handler matches this key?” and throws on a miss. A tag answers “give me all implementations” and has no key.

## Read configuration

Expose intention-revealing methods from the module Config:

```php
final class BillingConfig extends AbstractConfig
{
    public function retryAttempts(): int
    {
        return $this->getInt('billing.retry-attempts', 3);
    }
}
```

Available protected getters are `getString()`, `getInt()`, `getFloat()`, `getBool()`, `getArray()`, and untyped `get()`.

## Specialized tools

These APIs remain supported; use them when their more specific behavior is what you need:

| Tool | Use it when |
|---|---|
| `addBindingIf()` | A plugin supplies a default the application may override |
| `addFactory()` | Every resolution needs a new instance |
| `addProtected()` | The value itself is a closure and must not be invoked |
| `addAlias()` | One service needs another identifier |
| `addLazy()` / `#[Lazy]` | Construction is expensive and the service may remain unused |
| `extendService()` | Resolution must return a decorated or replaced service |
| `afterResolving()` | A resolved object needs an idempotent setter or similar hook |
| `when()->needs()->give()` | One consumer needs a contextual implementation or scalar |
| `loadDefinitions()` | Wiring is generated, shared, or environment-specific |
| `addExternalService()` | Bootstrap must hand a framework-owned object to Gacela |

See [Bindings](https://gacela-project.com/docs/bindings.md), [Provider](https://gacela-project.com/docs/provider.md), and [Service Map](https://gacela-project.com/docs/service-map.md) for the complete APIs.
