viames / pair
lightweight PHP framework as the air
Requires
- php: ^8.3||^8.4||^8.5
- ext-curl: *
- ext-intl: *
- ext-json: *
- ext-mbstring: *
- ext-pdo: *
- psr/log: ^1.1|^2.0|^3.0
Requires (Dev)
- phpunit/phpunit: ^12.0
Suggests
- ext-redis: *
- ext-xdebug: *
- dev-main / 4.x-dev
- v3.x-dev
- 3.0.1
- 3.0.0
- 3.0.0-alpha
- v2.x-dev
- 2.0.0
- 2.0.0-beta
- 2.0.0-alpha
- v1.x-dev
- 1.9.17
- 1.9.16
- 1.9.15
- 1.9.14
- 1.9.13
- 1.9.12
- 1.9.11
- 1.9.10
- 1.9.9
- 1.9.8
- 1.9.7
- 1.9.6
- 1.9.5
- 1.9.4
- 1.9.3
- 1.9.2
- 1.9.1
- 1.9
- 1.8.24
- 1.8.23
- 1.8.22
- 1.8.21
- 1.8.20
- 1.8.19
- 1.8.18
- 1.8.17
- 1.8.16
- 1.8.15
- 1.8.14
- 1.8.13
- 1.8.12
- 1.8.11
- 1.8.10
- 1.8.9
- 1.8.8
- 1.8.7
- 1.8.6
- 1.8.5
- 1.8.4
- 1.8.3
- 1.8.2
- 1.8.1
- 1.8
- 1.7.22
- 1.7.21
- 1.7.20
- 1.7.19
- 1.7.18
- 1.7.17
- 1.7.16
- 1.7.15
- 1.7.14
- 1.7.13
- 1.7.12
- 1.7.11
- 1.7.10
- 1.7.9
- 1.7.8
- 1.7.7
- 1.7.6
- 1.7.5
- 1.7.4
- 1.7.3
- 1.7.2
- 1.7.1
- 1.7.0
- 1.6.9
- 1.6.8
- 1.6.7
- 1.6.6
- 1.6.5
- 1.6.4
- 1.6.3
- 1.6.2
- 1.6.1
- 1.6.0
- 1.5.18
- 1.5.17
- 1.5.16
- 1.5.15
- 1.5.14
- 1.5.13
- 1.5.12
- 1.5.11
- 1.5.10
- 1.5.9
- 1.5.8
- 1.5.7
- 1.5.6
- 1.5.5
- 1.5.4
- 1.5.3
- 1.5.2
- 1.5.1
- 1.5.0
- 1.4.9
- 1.4.8
- 1.4.7
- 1.4.6
- 1.4.5
- 1.4.4
- 1.4.3
- 1.4.2
- 1.4.1
- 1.4.0
- 1.3.0
- 1.2.6
- 1.2.5
- 1.2.4
- 1.2.3
- 1.2.2
- 1.2.1
- 1.2.0
- 1.1.0
- 1.0.0
- dev-dependabot/composer/phpunit/phpunit-12.5.22
This package is auto-updated.
Last update: 2026-04-23 02:16:00 UTC
README
Pair is a lightweight PHP framework for server-rendered web applications. It focuses on fast setup, clear MVC routing, practical ORM features, and optional integrations (S3, SES, Telegram, Stripe, Push, Passkey) without heavy tooling.
What's New
Pair v4 is currently in alpha and may include breaking changes while the next major version is under development.
Pair v3 is the current stable release line on the v3 branch and through the ^3.0 tags.
Pair v4 now has an explicit core path built around:
Pair\Http\Inputfor immutable request inputPair\Data\ReadModelfor reusable HTML/API read contractsPair\Web\Controller+Pair\Web\PageResponsefor server-rendered actionsPair\Http\JsonResponsefor explicit JSON endpointsPair\Api\ApiExposable::readModelfor CRUD output contracts
OpenAPI generation for CRUD resources now follows the explicit response contract too: when a resource defines readModel, the generated response schema is built from that read model instead of the persistence class.
Pair\Core\Controller and Pair\Core\View now remain only as legacy MVC bridges in Pair v4 and emit deprecation notices in development or staging environments.
The Pair v3 to v4 upgrader is conservative on purpose: it rewrites only the low-risk patterns automatically and reports legacy controller/view flows that still need a manual migration.
For classic MVC modules it now also generates readonly *PageState skeletons from legacy View::assign() usage, so migration work starts from concrete typed-state files instead of ad-hoc arrays or magic view variables.
Quick Start
1) Install with Composer
composer require viames/pair
2) Bootstrap the application
<?php use Pair\Core\Application; require 'vendor/autoload.php'; $app = Application::getInstance(); $app->run();
3) Next Steps
4) Generate Pair v4 skeletons
vendor/bin/pair make:module orders vendor/bin/pair make:api api vendor/bin/pair make:crud order --table=orders --fields=id,customer_id,total_amount
The generator writes explicit Pair v4 files and avoids overwriting user-edited files unless --force is provided.
Why Pair
- Small and fast for small/medium projects.
- MVC structure with SEO-friendly routing.
- ActiveRecord-style ORM with automatic type casting.
- Installable Package architecture for ZIP-delivered modules, templates, providers, and custom package records.
- Runtime Extensions for explicit optional integrations.
- Good defaults for timezone, logging, and framework utilities.
- Optional third-party integrations when needed.
Core Features
ActiveRecord
Pair maps classes to DB tables and supports automatic casts (int, bool, DateTime, float, csv), relation helpers, and caching-oriented query helpers.
Docs: ActiveRecord
Routing Basics
Default route format (after base path):
/<module>/<action>/<params...>
Example: example.com/user/login
- module:
/modules/user - controller legacy path:
/modules/user/controller.php(extendsPair/Core/Controller.php, legacy bridge in v4) - action:
loginAction()when present - auto-loaded by the legacy MVC bridge:
model.php,viewLogin.php(UserViewLogin), and/modules/user/layouts/login.php
Docs: Router
Pair v4 Controller Path
Pair v4 prefers explicit responses over hidden controller/view bootstrapping:
<?php use Pair\Web\Controller; use Pair\Web\PageResponse; final class UserController extends Controller { /** * Render the default user page. */ public function defaultAction(): PageResponse { $state = new class ('Hello Pair v4') { /** * Store the page message. */ public function __construct(public string $message) {} }; return $this->page('default', $state, 'User'); } }
For reusable output contracts, Pair v4 prefers ReadModel objects built explicitly from persistence records.
Layout files in the v4 path should remain mostly HTML. Optional file-level preambles such as declare(strict_types=1) or /** @var UserPageState $state */ are only IDE/static-analysis hints and are not part of the runtime contract.
Minimal layout example:
<main class="user-page"> <h1><?= htmlspecialchars($state->message, ENT_QUOTES, 'UTF-8') ?></h1> </main>
Legacy Pair\Core\Controller and Pair\Core\View remain available only as a migration path and should not be used for new Pair v4 modules.
Log Bar and Debugging
Built-in log bar for loaded objects, memory usage, timings, SQL traces, backtraces, and custom debug messages.
Frontend Helpers
PairUI
Dependency-free helper for progressive enhancement in server-rendered apps (assets/PairUI.js).
Main directives:
data-text,data-html,data-show,data-ifdata-class,data-attr,data-prop,data-styledata-model,data-on,data-each
Docs: PairUI.js
PWA Helpers (No Build Step)
Available assets:
PairPWA.jsPairSW.jsPairRouter.jsPairSkeleton.jsPairDevice.jsPairPasskey.js
Minimal frontend setup:
<script src="/assets/PairUI.js" defer></script> <script src="/assets/PairPWA.js" defer></script> <script src="/assets/PairRouter.js" defer></script> <script src="/assets/PairSkeleton.js" defer></script> <script src="/assets/PairDevice.js" defer></script> <script src="/assets/PairPasskey.js" defer></script>
Important notes:
- Keep progressive enhancement.
- Service workers require HTTPS (except localhost).
- Use a single SW URL if you also enable Push.
Passkey Quick Start
Backend:
class ApiController extends \Pair\Api\PasskeyController {}
This enables:
POST /api/passkey/login/optionsPOST /api/passkey/login/verifyPOST /api/passkey/register/options(requiressid)POST /api/passkey/register/verify(requiressid)GET /api/passkey/list(requiressid)DELETE /api/passkey/revoke/{id}(requiressid)
Third-Party Integrations
Pair includes optional support for services such as:
In Pair v4 these integrations should be exposed through Runtime Extensions and manually registered adapters. This is separate from Installable Packages, the ZIP/manifest mechanism used for modules, templates, providers, and custom package records.
Configuration reference: Configuration (.env)
Upgrading
If you are upgrading a Pair v3 application to Pair v4:
composer run upgrade-to-v4 -- --dry-run composer run upgrade-to-v4 -- --write
To test unreleased Pair 4 development code from main:
composer require viames/pair dev-main
Additional migration and design docs:
Documentation
Main docs live in the Wiki. The release and branching workflow for the v3 stable / v4 dev transition is documented in RELEASING.md.
Useful pages:
- Generator
- Application
- Controller
- View
- ApiExposable
- CrudController
- Form
- Collection
- Push notifications
- index.php
- .htaccess
- classes
Requirements
| Software | Recommended | Minimum | Configuration |
|---|---|---|---|
| Apache | 2.4+ | 2.4 | modules: mod_rewrite |
| MySQL | 8.0+ | 8.0 | character_set: utf8mb4 collation: utf8mb4_unicode_ci storage_engine: InnoDB |
| PHP | 8.4+ | 8.3 | Composer-required extensions: curl, intl, json, mbstring, PDO |
Runtime notes:
pdo_mysqlis required when using the default MySQL driver (Pair\\Orm\\Database).fileinfois strongly recommended for reliable MIME detection in uploads.opensslis required only for Passkey/WebAuthn features.pcreandReflectionare part of standard PHP 8+ builds.
Example Project
Start from pair_boilerplate to bootstrap a new app quickly.
Benchmarks
The repository includes a lightweight benchmark harness for the new v4 path:
composer run benchmark-v4
It measures:
- minimal request bootstrap primitives
- simple server-rendered page rendering
- simple JSON endpoint payload preparation
- record-to-read-model mapping cost
- response serialization cost
Support
- Issues: github.com/viames/pair/issues
- Wiki: github.com/viames/pair/wiki
- Source: github.com/viames/pair/tree/main/src
- Homepage: viames.github.io/pair
Changelog
Version history is available in GitHub Releases: github.com/viames/pair/releases
Security
If you discover a security issue, follow the private reporting guidance in SECURITY.md.
Contributing
Feedback, code contributions, and documentation improvements are welcome via pull request.
License
MIT
