# Phred A PHP MVC framework: * Intended for projects of all sizes, and solo or team development. * The single router call per controller style makes it easy for teamwork without stepping on each others toes. * REQUIREMENTS * PHP 8.1+ * Primarily meant for Apache/Nginx webservers, will look into supporting other webservers in the future. * PSR-4 autoloading. * Installed through Composer (`composer create-project getphred/phred`) * Environment variables (.env) for configuration. * Supports two API formats (with content negotiation) * Pragmatic REST (default) * JSON:API * Choose via .env: * `API_FORMAT=rest` (plain JSON responses, RFC7807 error format) * `API_FORMAT=jsonapi` (JSON:API compliant documents and error objects) * Or negotiate per request using the `Accept` header: * `Accept: application/vnd.api+json` forces JSON:API for that request * TESTING environment variables (.env) * `TEST_RUNNER=codeception` * `TEST_PATH=tests` * `TEST_PATH` is relative to both project root and each module root. * Dependency Injection * Fully Pluggable, but ships with defaults: * Pluggability model * Core depends on Phred contracts (`Phred\Contracts\*`) and PSRs * Concrete implementations are provided by Service Providers. * Swap packages by changing `.env` and enabling a provider. * Driver keys (examples) * `ORM_DRIVER=pairity|doctrine` * `TEMPLATE_DRIVER=eyrie|twig|plates` * `FLAGS_DRIVER=flagpole|unleash` * `TEST_RUNNER=codeception` * Primary contracts * `Template\RendererInterface` * `Orm\EntityManagerInterface` (or repositories) * `Flags\FeatureFlagClientInterface` * `Testing\TestRunnerInterface`. * Default Plug-ins * Feature Flags through `getphred/flagpole` * ORM through `getphred/pairity` (handles migrations, seeds, and db access) * Unit Testing through `codeception/codeception` * Testing is provided as a CLI dev capability only; it is not part of the HTTP request lifecycle. * Template Engine through `getphred/eyrie` * Other dependencies: * Dependency Injection through `php-di/php-di` * Static Analysis through `phpstan/phpstan` * Code Style Enforcement through `friendsofphp/php-cs-fixer` * Logging through `monolog/monolog` * Config and environment handling through `vlucas/phpdotenv` * HTTP client through `guzzlehttp/guzzle` * CONTROLLERS * Invokable controllers (Actions), * Single router call per controller, * `public function __invoke(Request $request)` method entry point on controller class, * Response helpers via dependency injection: * Inject `Phred\Http\Contracts\ApiResponseFactoryInterface` to build responses consistently across formats. * The factory is negotiated per request (env default or `Accept` header) and sets appropriate `Content-Type`. * Common methods: `ok(array $data)`, `created(array $data, ?string $location)`, `noContent()`, `error(int $status, string $title, ?string $detail, array $extra = [])`. * Example: ```php use Phred\Http\Contracts\ApiResponseFactoryInterface as Responses; use Psr\Http\Message\ServerRequestInterface as Request; use Phred\Http\Middleware\ContentNegotiationMiddleware as Negotiation; final class ExampleController { public function __construct(private Responses $responses) {} public function __invoke(Request $request) { $format = $request->getAttribute(Negotiation::ATTR_API_FORMAT, 'rest'); return $this->responses->ok(['format' => $format]); } } ``` * VIEWS * Classes for data manipulation/preparation before rendering Templates, * `$this->render(, );` to render a template. * SERVICES * for business logic. * SERVICE PROVIDERS * for dependency injection. * MIGRATIONS * for database changes. * Modular separation, similar to Django apps. * Nested Models * Nested Controllers * Nested Views * Nested Services * Nested Migrations * Nested Service Providers * Nested Routes * Nested Templates * Nested Tests * CLI Helper called phred * `php phred create:command ` // Creates a CLI command under `console/commands * `php phred create:module ` // Creates a module * `php phred create::controller` // Creates a controller in the specified module * `php phred create::model` // Creates a model in the specified module * `php phred create::migration` // Creates a migration in the specified module * `php phred create::seed` // Creates a seeder in the specified module * `php phred create::test` // Creates a test in the specified module * `php phred create::view` / Creates a view in the specified module * `php phred db:backup` // Backup the database * `php phred db:restore -f ` // Restore the database from the specified backup file * `php phred migrate [-m ]` // Migrate entire project or module * `php phred migration:rollback [-m ]` // Rollback entire project or module * `php phred seed` * `php phred seed:rollback` * `php phred test[:]` // Test entire project or module * Runs tests using the configured test runner (dev only). * Requires `require-dev` dependencies. * `php phred run [-p ]` * Spawns a local PHP webserver on port 8000 (unless specified otherwise using `-p`) * CLI Helper is extendable through CLI Commands. Command discovery * Core commands (bundled with Phred) are discovered from `src/commands`. * User/project commands are discovered from `console/commands` in your project root. Run the CLI: ``` php phred list ``` Add your own command by creating a PHP file under `console/commands`, returning an instance of `Phred\Console\Command` (or an anonymous class extending it). (Or by running `php phred create:command `) Example: ``` writeln('Hello!'); return 0; } }; ``` Configuration and environment - Phred uses `vlucas/phpdotenv` to load a `.env` file from your project root (loaded in `bootstrap/app.php`). - Access configuration anywhere via `Phred\Support\Config::get(, )`. - Precedence: environment variables > config files > provided default. - Keys may be provided in either UPPER_SNAKE (e.g., `APP_ENV`) or dot.notation (e.g., `app.env`). - Config files live under `config/*.php` and return arrays; dot keys are addressed as `.` (e.g., `app.timezone`). Common keys - `APP_ENV` (default from config/app.php: `local`) - `APP_DEBUG` (`true`/`false`) - `APP_TIMEZONE` (default `UTC`) - `API_FORMAT` (`rest` | `jsonapi`; default `rest`) API formats and negotiation - Middleware `ContentNegotiationMiddleware` determines the active API format per request. - Precedence: 1. `Accept: application/vnd.api+json` → JSON:API 2. `.env`/config `API_FORMAT` (fallback to `rest`) - The chosen format is stored on the request as `phred.api_format` and used by the injected `ApiResponseFactoryInterface` to produce the correct response shape and `Content-Type`. - Demo endpoint: `GET /_phred/format` responds with the active format; `GET /_phred/health` returns a simple JSON 200. Examples ```php use Phred\Support\Config; $env = Config::get('APP_ENV', 'local'); // reads from env, then config/app.php, else 'local' $tz = Config::get('app.timezone', 'UTC'); // reads nested key from config files $fmt = strtolower(Config::get('API_FORMAT', 'rest')); ```