strictlyphp / dolphpin
Requires
- php: >=8.2
- ext-bcmath: *
- ext-curl: *
- ext-intl: *
- ext-mbstring: *
- ext-simplexml: *
- fig/http-message-util: ^1.1
- haydenpierce/class-finder: ^0.5.3
- league/route: ^6.2
- monolog/monolog: ^3.9
- nikic/php-parser: ^5
- php-di/php-di: ^7.0
- psr/http-server-handler: ^1.0
- psr/log: ^2.0 || ^3.0
- slim/psr7: ^1.7
Requires (Dev)
- php-coveralls/php-coveralls: ^2.7
- phpstan/phpstan: ^1.8
- phpstan/phpstan-phpunit: ^1.1
- phpunit/phpunit: ^9.5
- symplify/easy-coding-standard: ^11.1 || ^12.0 || ^13.0
This package is auto-updated.
Last update: 2026-03-25 20:57:04 UTC
README
Dolphin is a lightweight PHP framework designed for running serverless functions on DigitalOcean. It provides attribute-based routing, automatic DTO mapping, role-based access control, and dependency injection out of the box.
For a detailed look at the internals, see ARCHITECTURE.md.
Requirements
- PHP >= 8.2
- Extensions: intl, bcmath, simplexml, curl, mbstring
Installation
composer require strictlyphp/dolphin:^3.0
Quick Start
1. Define a Controller
Controllers are invokable classes annotated with #[Route]. The framework automatically deserializes the JSON request body into typed DTOs:
<?php declare(strict_types=1); namespace App\Controllers; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use StrictlyPHP\Dolphin\Attributes\Route; use StrictlyPHP\Dolphin\Request\Method; use StrictlyPHP\Dolphin\Response\JsonResponse; #[Route(Method::POST, '/users')] class CreateUserController { public function __invoke(CreateUserDto $dto, ServerRequestInterface $request): ResponseInterface { // $dto is automatically mapped from the JSON body return new JsonResponse(['id' => '123', 'name' => $dto->name], 201); } }
2. Define a DTO
DTOs are plain readonly classes. The framework maps JSON fields to constructor parameters, supporting scalars, value objects, nested DTOs, backed enums, and typed arrays:
<?php declare(strict_types=1); namespace App\Controllers; readonly class CreateUserDto { public function __construct( public string $name, public EmailAddress $email, ) { } }
3. Bootstrap the Application
Use App::build() in your DigitalOcean function entry point. Pass the namespace(s) containing your controllers — routes are discovered automatically from #[Route] attributes:
<?php use StrictlyPHP\Dolphin\App; function main(array $event, object $context): array { $app = App::build( controllers: ['App\Controllers'], ); return $app->run($event, $context); }
Features
Attribute-Based Routing
Routes are declared directly on controller classes using #[Route]:
#[Route(Method::GET, '/users/{id}')] class GetUserController { /* ... */ } #[Route(Method::DELETE, '/users/{id}')] class DeleteUserController { /* ... */ }
Supported HTTP methods: GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD.
Automatic DTO Mapping
Controller parameters that are class types are automatically deserialized from the JSON request body. The mapper supports:
- Scalar types —
string,int,float,bool - Value objects — Single-constructor-argument classes (e.g.
new EmailAddress($value)) - Nested DTOs — Recursively mapped from nested JSON objects
- Backed enums — Resolved via
::tryFrom() - Typed arrays — Element type declared via
@param array<Type>docblock annotations - Nullable parameters — Mapped to
nullwhen absent
Role-Based Access Control
Protect controllers with #[RequiresRoles]. The framework checks the authenticated user's roles before invoking the controller:
#[Route(Method::POST, '/admin/settings')] #[RequiresRoles(['ADMIN'])] class UpdateSettingsController { /* ... */ }
This requires middleware that sets a user attribute on the request implementing AuthenticatedUserInterface:
use StrictlyPHP\Dolphin\Authentication\AuthenticatedUserInterface; class AuthMiddleware implements MiddlewareInterface { public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { $user = // ... resolve authenticated user $request = $request->withAttribute('user', $user); return $handler->handle($request); } }
The AuthenticatedUserInterface requires getId(): string and getRoles(): array.
Dependency Injection
Dolphin uses PHP-DI for dependency injection. Pass container definitions to App::build():
$app = App::build( controllers: ['App\Controllers'], containerDefinitions: [ UserRepository::class => fn() => new UserRepository($db), ], );
Controllers are resolved through the container, so constructor dependencies are injected automatically.
Middleware
Register PSR-15 middleware globally via App::build():
$app = App::build( controllers: ['App\Controllers'], middlewares: [AuthMiddleware::class, CorsMiddleware::class], );
Debug Mode
Enable debug mode to include exception details (message, request body, stack trace) in error responses:
$app = App::build( controllers: ['App\Controllers'], debugMode: true, );
JSON Responses
Use JsonResponse for convenience:
use StrictlyPHP\Dolphin\Response\JsonResponse; return new JsonResponse(['key' => 'value']); // 200 return new JsonResponse(['created' => true], 201); // 201
Development
The project uses Docker for a consistent development environment. Available Make commands:
make install # Install dependencies make analyze # Run PHPStan static analysis (level 6) make style # Check coding style (ECS / PSR-12) make style-fix # Auto-fix coding style issues make coveralls # Run tests with coverage make check-coverage # Check test coverage of changed files
License
This project is licensed under the MIT License.