ShiftPHP is moving toward an API-only modular monolith. View templates, compiled view storage, page assets and MVC rendering are out of scope for this line.
- API-only runtime direction.
- Route parameters with
{name}placeholders. - Controller actions returning response objects.
-
Shift\Response\Response,JsonResponseandResponseEmitter. - JSON response helpers on the base controller.
- Request helpers for query, post, input, raw body, JSON and route params.
- JSON errors for
400,404and500. -
405 Method Not Allowedwith anAllowheader. - Lightweight API core tests through
composer test. -
route:listCLI command. - PHP 8 attributes for controller routing.
- PHP 8 attributes for response metadata and parameter binding.
- Modular monolith support through
application/modules/*/Module.php. - Module-owned controllers, routes, services and commands.
- Middleware pipeline.
- Controller autowiring through the container.
- Validation helpers and typed request DTOs.
- CORS middleware.
- Authentication and authorization middleware contracts.
- Module configuration loading.
- Module lifecycle hooks, for example
boot()after service registration. - Framework source moved to
src/for package split preparation. - CLI create generators for modules and module-owned classes with file-based stubs.
-
.envloading for application configuration. - Native PDO database configuration, lazy connection, and basic query API.
- Fluent query builder and attribute-driven database models.
- CLI diagnostics for tests, runtime info, environment, database, and modules.
- CLI help listing and command-specific usage.
- Centralized CLI command registry shared by the dispatcher and help command.
- CLI command metadata through attributes, aliases, and grouped help.
-
shift doctorproject diagnostics. - Database migrations with create, migrate, status, and rollback commands.
- Module discovery cache for production.
- Structured exception logging with JSON file logger and service container override.
- Request id lifecycle with generated
X-Request-Idresponse headers and log context. - Developer documentation organized into a Laravel-like guide.
- CLI quality gate with
shift lintandshift qa. - OpenAPI JSON generation from registered module routes with
shift openapi. - OpenAPI documentation attributes, validation, and live Swagger-like viewer.
- Removal of view storage and example page assets from runtime.
- Removal of legacy
application/controllersandapplication/routes.php. - Domain-oriented framework namespaces:
Shift\ResponseShift\Routing\RouterShift\Routing\AttributesShift\ServiceShift\Modules
- GitHub API workflow with PHP 8.3 checks.
- PR version label validation.
- Release workflow using PR summary as release notes.
- Split API core tests into runner, support, fixtures, and feature files.
Each module can own:
- controllers,
- routes,
- services,
- commands.
Module layout:
application/modules/{ModuleName}/
├── Module.php
├── Controllers/
├── Services/
└── Commands/
Module.php is the module boundary. It registers services into the container, routes into the router, and command mappings into the CLI.
Request
-> App
-> Middleware pipeline
-> Router
-> Controller action
-> Response
-> ResponseEmitter
Routes live inside modules:
class Module extends AbstractModule
{
public function registerRoutes(Router $router): void
{
(new AttributeRouteLoader())->load($router, [
HealthController::class,
]);
}
}Supported methods:
GETPOSTPUTPATCHDELETE
Controllers receive the current Request and ServiceContainer through the constructor. Actions should return Response or JsonResponse.
class HealthController extends \Shift\Controller
{
#[Get('/api/{argument}')]
public function api(#[PathParam] string $argument, #[QueryParam('include')] ?string $include = null): JsonResponse
{
return $this->json([
'argument' => $argument,
'include' => $include,
]);
}
#[Post('/created')]
#[Status(201)]
public function created(#[Body('name')] string $name): array
{
return ['name' => $name];
}
}Action arguments are resolved from route parameter names. An action can also type-hint Shift\Request.
Errors are emitted as JSON:
{
"error": {
"message": "Endpoint not found",
"status": 404
}
}Internal errors return a generic 500 message unless display_errors is enabled.
- legacy
Engine/View - legacy view namespace
- legacy
Engine/Utils/Storage.php - legacy
Engine/Error/StorageError.php - example CSS and JS page assets
View\\composer namespaceapplication/controllersapplication/routes.php
- Deeper static analysis for framework contracts and type safety.