PHPackages                             cohete/skeleton - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. cohete/skeleton

ActiveProject[Framework](/categories/framework)

cohete/skeleton
===============

Skeleton project for Cohete async PHP framework

01PHPCI passing

Since Mar 31Pushed 2mo agoCompare

[ Source](https://github.com/pascualmg/cohete-skeleton)[ Packagist](https://packagist.org/packages/cohete/skeleton)[ RSS](/packages/cohete-skeleton/feed)WikiDiscussions main Synced 3w ago

READMEChangelogDependenciesVersions (8)Used By (0)

Cohete Skeleton
===============

[](#cohete-skeleton)

Starter project for Cohete async PHP.

Quick Start
-----------

[](#quick-start)

```
git clone
cd cohete-skeleton
composer install
make run
curl localhost:8080/health
```

Sin dependencias externas. Arranca con almacenamiento en memoria y bus de eventos local. Listo para desarrollar.

Endpoints
---------

[](#endpoints)

MethodPathDescriptionGET`/health`Health checkGET`/todos`List all todosPOST`/todos`Create a new todoGET`/todos/{id}`Get a todo by IDPUT`/todos/{id}`Update a todoDELETE`/todos/{id}`Delete a todoArchitecture
------------

[](#architecture)

El skeleton demuestra como construir una app async con infraestructura intercambiable. El dominio no sabe que base de datos ni que bus de mensajes usa -- todo se decide en `bootstrap.php` via variables de entorno.

```
                     ┌─────────────────────────────┐
                     │          Domain              │
                     │  Todo, TodoId, TodoRepository│
                     │  TodoCreated (domain event)  │
                     └──────────┬──────────────────┘
                                │ interfaces
                ┌───────────────┼───────────────┐
                │               │               │
     ┌──────────▼───┐  ┌───────▼──────┐  ┌─────▼──────────┐
     │  Repository   │  │  Message Bus  │  │   Controller   │
     │  (storage)    │  │  (events)     │  │   (HTTP)       │
     └──────┬───────┘  └──────┬────────┘  └────────────────┘
            │                 │
     ┌──────┴───────┐  ┌─────┴──────────┐
     │ InMemory     │  │ ReactMessageBus│ ← default (framework)
     │ MySQL        │  │ BunnieMessageBus│ ← RabbitMQ
     └──────────────┘  └────────────────┘

```

### Infrastructure Switching

[](#infrastructure-switching)

Todo se controla con variables de entorno. Sin ellas, todo corre in-memory:

VariableQue activa`MYSQL_HOST``MysqlTodoRepository` en lugar de `InMemoryTodoRepository``RABBITMQ_HOST``BunnieMessageBus` en lugar de `ReactMessageBus`Ejemplo: solo MySQL, bus in-memory:

```
echo "MYSQL_HOST=127.0.0.1" > .env
echo "MYSQL_USER=cohete" >> .env
echo "MYSQL_PASSWORD=cohete" >> .env
echo "MYSQL_DATABASE=cohete_skeleton" >> .env
make run
```

Ejemplo: MySQL + RabbitMQ:

```
cp .env.example .env
# descomenta las lineas de RABBITMQ
make run
```

Sin `.env`: todo in-memory, zero dependencias externas.

Message Bus
-----------

[](#message-bus)

El bus de mensajes transporta domain events. Cuando un Todo se crea, el repository publica un `TodoCreated` event. Los subscribers reaccionan (logear, notificar, lo que sea).

### Interfaz comun

[](#interfaz-comun)

Ambas implementaciones cumplen la misma interfaz del framework:

```
interface MessageBus
{
    public function publish(Message $message): void;
    public function subscribe(string $messageName, callable $listener): void;
}
```

### ReactMessageBus (default, in-memory)

[](#reactmessagebus-default-in-memory)

Viene con `cohete/framework`. Usa `EventEmitter` + `futureTick()`. Los eventos viajan dentro del mismo proceso. Si el proceso muere, se pierden. Perfecto para desarrollo y apps simples.

No necesita configuracion. El `ContainerFactory` del framework lo registra automaticamente.

### BunnieMessageBus (RabbitMQ)

[](#bunniemessagebus-rabbitmq)

Los eventos viajan por AMQP a traves de RabbitMQ. Varios procesos pueden subscribirse al mismo exchange. Si un consumer muere, los mensajes esperan en la cola. Para produccion real.

Se activa poniendo `RABBITMQ_HOST` en el entorno. El bootstrap sobreescribe `MessageBus::class` en el container:

```
if ($useRabbit) {
    $definitions[MessageBus::class] = static fn () => new BunnieMessageBus([
        'host'     => getenv('RABBITMQ_HOST'),
        'port'     => (int)(getenv('RABBITMQ_PORT') ?: 5672),
        'user'     => getenv('RABBITMQ_USER') ?: 'guest',
        'password' => getenv('RABBITMQ_PASSWORD') ?: 'guest',
        'vhost'    => getenv('RABBITMQ_VHOST') ?: '/',
    ]);
}
```

### Como funciona el async (bunny 0.6)

[](#como-funciona-el-async-bunny-06)

Bunny 0.6 usa `React\Socket\ConnectionInterface` internamente. El API parece sincrono pero por debajo usa Fibers y el event loop de ReactPHP:

```
// Parece bloqueante, pero NO lo es:
$client = new Client($options);
$client->connect();           // internamente: await(promesa del handshake AMQP)
$channel = $client->channel();
```

Cuando llamas a `connect()`:

1. Abre un socket TCP via ReactPHP (no-bloqueante)
2. `await()` suspende la Fiber actual
3. El event loop procesa el handshake AMQP
4. La Fiber se resume y `connect()` retorna

Tu codigo escribe como si fuera sincrono. El event loop sigue vivo procesando HTTP requests mientras tanto.

Para `consume()`: registra un callback en la conexion. Cada vez que llega un mensaje por el socket, el event loop lo lee, bunny lo parsea, y ejecuta tu callback. No hay polling. El mismo loop que sirve HTTP sirve AMQP.

### Flujo de un domain event

[](#flujo-de-un-domain-event)

```
POST /todos
    → CreateTodoController
    → Todo::create() graba TodoCreated event en el aggregate
    → Repository::save() hace pullDomainEvents()
    → MessageBus::publish(TodoCreated)
    → [ReactMessageBus]  EventEmitter::emit() en el proximo tick
      [BunnieMessageBus] channel->publish() al exchange "cohete_events"
                         routing key: "domain_event.todo_created"
    → RabbitMQ rutea al queue del subscriber
    → consume() callback → TodoCreatedSubscriber
    → Logger: "Todo created {id, title}"

```

### Gotcha: queueBind en bunny 0.6

[](#gotcha-queuebind-en-bunny-06)

La firma es `queueBind($exchange, $queue, $routingKey)` -- exchange primero. En la mayoria de clientes AMQP es al reves. Si los inviertes, RabbitMQ dice `NOT_FOUND - no exchange 'amq.gen-xxxxx'`.

MySQL Mode
----------

[](#mysql-mode)

Se activa con `MYSQL_HOST`. El bootstrap crea un `MysqlClient` (react/mysql, async) y registra `MysqlTodoRepository`:

```
$definitions[MysqlClient::class] = static fn () => new MysqlClient(
    sprintf('%s:%s@%s:%s/%s', $user, $pass, $host, $port, $db)
);
$definitions[TodoRepository::class] = static function (ContainerInterface $c) {
    return new MysqlTodoRepository(
        $c->get(MysqlClient::class),
        $c->get(MessageBus::class),
    );
};
```

El schema se crea con `schema.sql` (auto-loaded por docker compose).

Docker Compose
--------------

[](#docker-compose)

Levanta la app con MySQL y RabbitMQ:

```
cp .env.example .env
docker compose up -d
```

Servicios incluidos:

- **cohete**: la app PHP (puerto 8080)
- **mysql**: MySQL 8.0 (puerto 3306, schema auto-loaded)
- **rabbitmq**: RabbitMQ 3 + management UI (puertos 5672/15672)

MCP (Model Context Protocol)
----------------------------

[](#mcp-model-context-protocol)

The skeleton includes MCP so AI agents can interact with your app from day one.

**Local (stdio)** -- for development, your agent calls your domain directly:

```
php src/mcp-server.php
```

ToolDescription`list_todos`List all todos`get_todo`Get a todo by UUID`create_todo`Create a new todo`update_todo`Update title/completed`delete_todo`Delete a todoTools live in `src/MCP/TodoToolHandlers.php`. Add your own by adding methods with `#[McpTool]` attribute.

**Remote (SSE/HTTP)** -- integrated into the HTTP server. Same process, same state:

```
# Connect Claude Code
claude mcp add my-app --transport sse http://localhost:8080/mcp/sse
```

Create data via MCP, see it in the browser. Same memory, same event loop.

> The skeleton ships with batteries included. If you don't need MCP, MySQL, or RabbitMQ, remove them. If you leave them, unused features don't affect performance -- they only load when activated via env vars.

Project Structure
-----------------

[](#project-structure)

```
.
├── config/
│   └── routes.json              # HTTP routing
├── public/
│   ├── index.html               # Frontend entry point
│   └── js/components/           # Web Components (vanilla JS, Shadow DOM)
├── src/
│   ├── Bus/
│   │   └── BunnieMessageBus.php # RabbitMQ message bus
│   ├── Controller/              # HTTP request handlers
│   ├── Domain/                  # Entities, Value Objects, interfaces, Events
│   ├── MCP/
│   │   └── TodoToolHandlers.php # MCP tool handlers (shared by all transports)
│   ├── Repository/
│   │   ├── InMemoryTodoRepository.php  # Default (no deps)
│   │   └── MysqlTodoRepository.php     # Async MySQL
│   ├── Subscriber/
│   │   └── TodoCreatedSubscriber.php   # Event handler
│   ├── bootstrap.php            # HTTP server entry point
│   └── mcp-server.php           # MCP stdio server (local dev)
├── schema.sql                   # MySQL schema
├── .env.example                 # Config template
├── docker-compose.yml           # App + MySQL + RabbitMQ
├── Dockerfile                   # Multi-stage production image
├── Makefile                     # Common tasks
└── composer.json                # Dependencies

```

How to add a new endpoint
-------------------------

[](#how-to-add-a-new-endpoint)

1. **Create a Controller** in `src/Controller/` implementing `Cohete\HttpServer\HttpRequestHandler`.
2. **Register the Route** in `config/routes.json`.
3. **Register Dependencies** in `ContainerFactory::create()` call in `src/bootstrap.php`.

Links
-----

[](#links)

- [cohete/framework](https://github.com/pascualmg/cohete-framework)
- [cohete/ddd](https://github.com/pascualmg/cohete-ddd)

License
-------

[](#license)

MIT License - see [LICENSE](LICENSE).

###  Health Score

21

—

LowBetter than 18% of packages

Maintenance56

Moderate activity, may be stable

Popularity1

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity19

Early-stage or recently created project

 Bus Factor1

Top contributor holds 77.8% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/11436672?v=4)[Pascual Muñoz ](/maintainers/pascualmg)[@pascualmg](https://github.com/pascualmg)

---

Top Contributors

[![pascualmg](https://avatars.githubusercontent.com/u/11436672?v=4)](https://github.com/pascualmg "pascualmg (7 commits)")[![google-labs-jules[bot]](https://avatars.githubusercontent.com/in/842251?v=4)](https://github.com/google-labs-jules[bot] "google-labs-jules[bot] (2 commits)")

### Embed Badge

![Health badge](/badges/cohete-skeleton/health.svg)

```
[![Health](https://phpackages.com/badges/cohete-skeleton/health.svg)](https://phpackages.com/packages/cohete-skeleton)
```

###  Alternatives

[laravel/socialite

Laravel wrapper around OAuth 1 &amp; OAuth 2 libraries.

5.7k104.3M829](/packages/laravel-socialite)[laravel/dusk

Laravel Dusk provides simple end-to-end testing and browser automation.

1.9k38.6M289](/packages/laravel-dusk)[pinguo/php-msf

Pinguo Micro Service Framework For PHP

1.7k4.2k](/packages/pinguo-php-msf)[nineinchnick/edatatables

Grid widget for the Yii Framework, wrapper for the DataTables jQuery plugin

173.2k](/packages/nineinchnick-edatatables)[link-cloud/fast-hyperf

LinkCloud Fast Hyperf

241.2k1](/packages/link-cloud-fast-hyperf)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
