compose

Getting Started

This guide walks through installing Compose, bootstrapping the starter pipeline, and serving a simple page. It assumes a clean directory and access to PHP 8.3 with Composer installed.

Prerequisites

1. Install the Framework

Create a new project directory and require Compose:

mkdir my-compose-app
cd my-compose-app
composer init --name="acme/hello-compose" --require="php:~8.3" --quiet
composer require phpcompose/compose:^1.0@rc

Composer will install the framework along with Laminas PSR-7 components.

2. Bootstrap the Front Controller

Create a public/ directory with an index.php file. This is the entry point that bootstraps the pipeline.

<?php
declare(strict_types=1);

use Compose\Starter;

require __DIR__ . '/../vendor/autoload.php';

// load or compose your configuration array
$config = require __DIR__ . '/../config/app.php';

Starter::start($config);

The starter builds an instance of Compose\Http\Pipeline, pipes the default middleware stack, and starts listening for requests.

3. Define Configuration

Next, add a config/app.php file. Start with the baseline framework configuration and merge your overrides:

<?php
declare(strict_types=1);

use Compose\Config;

$base = (new Config())();

return array_replace_recursive($base, [
    'app' => [
        'name' => 'Hello Compose',
    ],
    'template' => [
        'layout' => 'layouts::app',
        'folders' => [
            'layouts' => __DIR__ . '/../layouts',
        ],
    ],
    'pages' => [
        'dir' => __DIR__ . '/../pages',
    ],
]);

Configuration is stored as an array (or Compose\Support\Configuration instance) and injected into the service container. You can override services, middleware, routes, subscribers, and template renderer settings the same way. The value layouts::app tells the renderer to use the app.phtml script inside the folder that was aliased as layouts in the configuration above.

4. Add Layouts and Pages

Compose ships with a Pages middleware (the primary feature) that renders templates with optional code-behind scripts. Add the following files:

layouts/app.phtml

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title><?= $this->e($title ?? 'Compose App') ?></title>
</head>
<body>
<?= $this->section('content') ?>
</body>
</html>

pages/index.phtml

<?php $this->layout('layouts::app', ['title' => $title ?? 'Compose Demo']); ?>

<h1><?= $this->e($title ?? 'Hello from Compose') ?></h1>
<p><?= $this->e($message ?? 'This response came from pages/index.phtml.') ?></p>

pages/index.phtml.php

<?php
use Psr\Http\Message\ServerRequestInterface;

return static function (ServerRequestInterface $request): array {
    return [
        'title' => 'Compose Demo',
        'message' => 'Hello from the Pages middleware!',
    ];
};

The .phtml.php suffix lets you keep the view template and an optional script together. When the page file returns an array, the value is passed to the template as data. Returning a ResponseInterface short-circuits the rendering pipeline. If no code-behind script is present, the template runs on its own.

5. Serve the Application

Run the built-in PHP development server from the project root:

php -S 0.0.0.0:8080 -t public/

Visit http://localhost:8080 to see the app. The starter wires the following middleware by default:

  1. Output buffering middleware.
  2. Laminas OriginalMessages.
  3. JSON/form body parsing.
  4. Application middleware stack (middleware config key).
  5. MVC middleware with routing and pages support.
  6. Not Found middleware.

6. Where to Go Next