debuss-a / piccolo
A PSR-15 application skeleton built on Laminas Stratigility and Mezzio components, with League Container, attribute-based routing, and a DDD-layered structure.
Requires
- php: ^8.4
- ext-pdo: *
- borschphp/config: ^1.4
- debuss-a/attribute-routing: ^1.1
- debuss-a/awareness: ^1.2
- filp/whoops: ^2.18
- laminas/laminas-db: ^2.22
- laminas/laminas-diactoros: ^3.8
- laminas/laminas-httphandlerrunner: ^2.13
- laminas/laminas-stratigility: ^4.3
- league/container: ^5.2
- matthiasmullie/scrapbook: ^1.5
- mezzio/mezzio-fastroute: ^3.14
- mezzio/mezzio-helpers: ^5.20
- mezzio/mezzio-platesrenderer: ^2.14
- mezzio/mezzio-problem-details: ^1.19
- monolog/monolog: ^3.10
- php-http/curl-client: ^2.4
Requires (Dev)
- pestphp/pest: ^5.1
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-09-01 20:35:30 UTC
README
Piccolo is a lightweight PHP skeleton inspired by the Mezzio Skeleton App, designed to keep the same PSR-first architecture with less bootstrap complexity.
It uses Laminas and Mezzio components directly (without mezzio/mezzio) and provides a clean, editable Application layer, attribute-based routing, and service-provider-driven dependency injection.
Goals
- Keep a simple starting point for modern PSR-7 / PSR-15 applications
- Preserve strong architectural boundaries (Application / Domain / Infrastructure)
- Reduce boilerplate around container wiring and route registration
- Stay framework-agnostic enough to evolve with your project
Tech Stack
- Runtime
- PHP 8.4+
laminas/laminas-stratigilitylaminas/laminas-httphandlerrunnerlaminas/laminas-diactoros
- Routing
mezzio/mezzio-fastroutedebuss-a/attribute-routing(attribute route collector)
- Container
league/container+ Service Providers + ReflectionContainer
- Configuration
borschphp/config(with.envsupport and optional cache)
- Templating
mezzio/mezzio-platesrenderer(Plates)
- Error handling / API errors
filp/whoopsmezzio/mezzio-problem-details(RFC 7807)
- Observability & utilities
monolog/monologmatthiasmullie/scrapbook(PSR-6 + PSR-16 cache)
- HTTP client example
php-http/curl-client
Getting Started
composer install cp .env.example .env composer serve
Application runs at: http://localhost:8080
Project Structure
.
├── bootstrap/ # global defines + helper path functions
├── config/
│ ├── container.php # League\Container wiring + service providers
│ ├── pipeline.php # middleware pipeline
│ └── routes.php # attribute route loader + manual routes
├── public/
│ └── index.php # front controller
├── src/
│ ├── Application/ # HTTP layer: handlers, middleware, service providers
│ ├── Domain/ # business contracts/models/shared concepts
│ └── Infrastructure/ # external integrations (HTTP client, persistence...)
└── storage/
├── cache/
├── logs/
├── openapi.yaml
└── templates/
Core Architecture
1) Custom Application class
The skeleton includes a rewritten Application class in src/Application/Application.php.
It mirrors the familiar Mezzio app flow while keeping the entry point fully editable for teams.
2) Container with Service Providers
config/container.php uses league/container and registers focused service providers:
- HTTP factories (PSR-17)
- Request handler runner
- Router (FastRoute)
- Error handler
- Logger
- Cache
- Database adapter
- Template renderer
- Problem Details middleware
- HTTP client
The debuss-a/awareness package is used to inject common dependencies into Aware classes after resolution (e.g. logger, factories, container), which helps keep constructors small.
3) Routing strategy
Piccolo supports:
- Attribute-based routing in handlers (default)
- Optional manual route registration in
config/routes.php
Attributes are collected via AttributeRouteLoader on Application\Handler.
4) Middleware pipeline
config/pipeline.php keeps a Mezzio-style flow:
ErrorHandler/apiscoped middlewares (ProblemDetailsMiddleware,BodyParamsMiddleware)RouteMiddlewareImplicitHeadMiddlewareImplicitOptionsMiddlewareMethodNotAllowedMiddlewareDispatchMiddlewareNotFoundHandler
Built-in Endpoints
GET /— home page (or JSON fallback)GET /api/ping— lightweight ping endpointGET /api/health— global health check + DB/cache connection statusGET /api/v1/posts— posts example list (JSONPlaceholder)GET /api/v1/posts/{id}— post by idGET /api/v1/openapior/api/v1/openapi.yaml— OpenAPI documentGET /api/v1/redoc(or/api/v1/swagger) — ReDoc UI
OpenAPI and ReDoc
The API contract is stored in:
storage/openapi.yaml
The ReDoc handler renders documentation directly from the route-generated OpenAPI URL, so docs stay aligned with your app URLs.
Configuration
Environment defaults live in .env.example:
APP_NAMEAPP_VERSIONAPP_URLAPP_ENVLOGGER_NAMETIMEZONEDB_DRIVERDB_DATABASE
Production mode is controlled by APP_ENV=production and enables config/router caching behavior where configured.
Testing
Pest is included as a dev dependency:
./vendor/bin/pest
Extending the Skeleton
- Add new handlers in
src/Application/Handler - Declare routes via attributes (or manually in
config/routes.php) - Register app services in
config/container.phpor dedicated service providers - Keep business logic in
Domain, and external IO inInfrastructure
Piccolo is intentionally pragmatic: small enough to start quickly, structured enough to scale cleanly.