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

# Trait ForwardsCalls

> Aprende cómo implementar de forma segura el reenvío de métodos en clases proxy/decorator usando Illuminate\Support\Traits\ForwardsCalls.

## Qué es el trait ForwardsCalls

`Illuminate\Support\Traits\ForwardsCalls` es un trait que unifica la delegación de métodos hacia otro objeto. En el propio Laravel se usa en objetos "envoltorio" como los de Eloquent y Mail.

<Info>
  La implementación está en `src/Illuminate/Support/Traits/ForwardsCalls.php`. Cuando se reenvía un método inexistente, relanza el error como una `BadMethodCallException` que incluye el nombre de la clase que hizo la llamada.
</Info>

```mermaid theme={null}
flowchart LR
  A["Tu clase Proxy"] -->|__call| B["forwardCallTo()"]
  B --> C["Driver / Builder interno"]
  C --> D["Devuelve el resultado"]
  D --> A
```

## API principal

### `forwardCallTo($object, $method, $parameters)`

Reenvía la llamada al objeto indicado tal cual. Normalmente se invoca desde `__call()`.

### `forwardDecoratedCallTo($object, $method, $parameters)`

Se usa en builders o decorators cuando quieres mantener la cadena. Si el valor devuelto por el método reenviado es el «propio objeto destino», lo sustituye por el «objeto de origen (`$this`)» y lo devuelve.

### Combinación con `__call()` / `__callStatic()`

`ForwardsCalls` no aporta los métodos mágicos. Tú debes implementar `__call()` (y si hace falta `__callStatic()`) en tu clase y llamar dentro a los métodos `forwardCallTo*`.

## Ejemplos reales (interior de Laravel)

<Steps>
  <Step title="Los Facades ofrecen un static proxy">
    `Illuminate\Support\Facades\Facade` delega directamente en la root instance mediante `__callStatic()`. Como el Facade se invoca de forma estática, no usa `ForwardsCalls`, sino un reenvío directo.
  </Step>

  <Step title="Eloquent Builder usa forwardCallTo">
    `Illuminate\Database\Eloquent\Builder::__call()` pasa los métodos no resueltos al query builder interno con `forwardCallTo($this->query, ...)` y devuelve `$this` al final para mantener la fluent chain.
  </Step>

  <Step title="Relation / Mail / Event usan forwardDecoratedCallTo">
    En `Illuminate\Database\Eloquent\Relations\Relation`, `Illuminate\Mail\Message` y `Illuminate\Events\NullDispatcher` se emplea `forwardDecoratedCallTo`, delegando en el objeto interno pero preservando la cadena de la API exterior.
  </Step>
</Steps>

## Implementación básica de un proxy (`forwardCallTo`)

```php theme={null}
use Illuminate\Support\Traits\ForwardsCalls;

class CourierProxy
{
    use ForwardsCalls;

    public function __construct(
        protected CourierDriver $driver
    ) {}

    public function __call(string $method, array $parameters): mixed
    {
        return $this->forwardCallTo($this->driver, $method, $parameters);
    }
}
```

Con esta forma, `CourierProxy` expone de forma transparente toda la API pública de `CourierDriver`.

## Proxy con method chaining (`forwardDecoratedCallTo`)

```php theme={null}
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Traits\ForwardsCalls;

class QueryProxy
{
    use ForwardsCalls;

    public function __construct(
        protected Builder $query
    ) {}

    public function __call(string $method, array $parameters): static
    {
        $this->forwardDecoratedCallTo($this->query, $method, $parameters);

        return $this;
    }

    public function get(): \Illuminate\Support\Collection
    {
        return $this->query->get();
    }
}
```

```php theme={null}
$users = (new QueryProxy(User::query()))
    ->where('active', true)
    ->orderByDesc('created_at')
    ->limit(10)
    ->get();
```

<Tip>
  Es más seguro apoyarse en la regla de `forwardDecoratedCallTo` de «si el retorno es el objeto destino, se sustituye por `$this`» que escribir manualmente `return $this`.
</Tip>

## Lanzamiento automático de BadMethodCallException

Cuando llamas a un método inexistente, `ForwardsCalls` relanza una `BadMethodCallException` usando el nombre de la clase que originó la llamada.

```php theme={null}
try {
    (new CourierProxy($driver))->missingMethod();
} catch (\BadMethodCallException $e) {
    // p. ej.: Call to undefined method App\Services\CourierProxy::missingMethod()
    report($e);
}
```

Así, los usuarios pueden localizar de inmediato en qué API externa se produjo el fallo.

## Comparación con Macroable

| Aspecto              | `Macroable`                                  | `ForwardsCalls`                               |
| -------------------- | -------------------------------------------- | --------------------------------------------- |
| Objetivo             | Añadir métodos nuevos a una clase existente. | Delegar métodos a otro objeto.                |
| Entradas principales | `macro()`, `mixin()`                         | `forwardCallTo()`, `forwardDecoratedCallTo()` |
| Casos adecuados      | Extensión de API.                            | Proxy / Decorator / Adapter.                  |

<Warning>
  Si lo que quieres es «añadir métodos» y usas `ForwardsCalls`, cualquier método que no exista en el objeto destino fallará siempre. Si tu objetivo es extender la API, elige `Macroable`.
</Warning>

## Ejemplos de uso en el desarrollo de paquetes

### 1) Manager que cambia de driver

```php theme={null}
use Illuminate\Support\Traits\ForwardsCalls;

class SmsManager
{
    use ForwardsCalls;

    public function __construct(
        protected SmsDriver $driver
    ) {}

    public function via(string $name): static
    {
        $this->driver = app(SmsDriverFactory::class)->make($name);

        return $this;
    }

    public function __call(string $method, array $parameters): mixed
    {
        return $this->forwardCallTo($this->driver, $method, $parameters);
    }
}
```

### 2) Adapter con varios backends

Puedes unificar backends distintos (HTTP / Queue / WebSocket) tras una única API común y delegar en cada uno.

### 3) Spy / Stub para tests

En lugar del driver real, inyectas un Spy y dejas pasar las llamadas con `forwardCallTo` para verificar cuántas veces se llamó y con qué argumentos.

## Páginas relacionadas

<Columns cols={2}>
  <Card title="Trait Macroable" icon="puzzle-piece" href="/es/advanced/macroable">
    Aprende el patrón para extender clases existentes con nuevos métodos.
  </Card>

  <Card title="Trait Conditionable" icon="git-branch" href="/es/advanced/conditionable">
    Aprende a diseñar cadenas con bifurcaciones condicionales mediante `when()` / `unless()`.
  </Card>
</Columns>


## Related topics

- [Trait Macroable](/es/advanced/macroable.md)
- [Seeding de base de datos](/es/seeding.md)
- [Trait Conditionable](/es/advanced/conditionable.md)
- [Trait Dumpable](/es/advanced/dumpable.md)
- [Clase Fluent](/es/advanced/fluent.md)
