viames / pair
Lightweight PHP framework for fast server-rendered web applications with MVC routing, ActiveRecord ORM and API tooling
Package info
pkg:composer/viames/pair
Requires
- php: ^8.4.1
- ext-curl: *
- ext-intl: *
- ext-json: *
- ext-mbstring: *
- ext-pdo: *
- ext-pdo_mysql: *
- psr/log: ^1.1 || ^2.0 || ^3.0
Requires (Dev)
- phpunit/phpunit: ^13.0
Suggests
- ext-fileinfo: Recommended for reliable MIME detection in uploads.
- ext-openssl: Required for Passkey/WebAuthn features.
- ext-redis: Recommended for Redis-backed cache/session integrations.
- ext-xdebug: Useful while debugging Pair applications and tests.
- aws/aws-sdk-php: Required by Pair\Services\AmazonS3 for AWS S3 and S3-compatible object storage.
- stripe/stripe-php: Required by Pair\Services\StripeGateway for Stripe payments.
This package is auto-updated.
Last update: 2026-08-24 11:54:00 UTC
README
Lightweight PHP framework for fast server-rendered web applications.
Website · Wiki · Boilerplate · Issues · Releases · Security
Pair is a lightweight PHP framework for server-rendered web applications. It focuses on fast setup, clear MVC routing, practical ActiveRecord-style ORM features, API tooling, progressive enhancement and optional integrations without heavy tooling.
Pair is designed for small and medium web applications where you want a clear PHP/MySQL stack, server-rendered pages, useful defaults, low operational overhead and a framework that remains easy to inspect, extend and maintain.
Version status
| Line | Status | Recommended use |
|---|---|---|
| Pair v4 | Stable / production | Current applications and new development |
| Pair v3 | Maintenance | Existing applications pinned to v3 releases |
Pair v4 is the current stable line and is used in production across the maintainer's applications. Pair v3 remains available as a maintenance line for existing applications that have not yet migrated.
Quick start
1. Install Pair v4
composer require viames/pair:^4.0
2. Bootstrap the application
<?php use Pair\Core\Application; require __DIR__ . '/vendor/autoload.php'; $app = Application::getInstance(); $app->run();
3. Start from the boilerplate
For a ready-to-use application structure, start from:
https://github.com/viames/pair_boilerplate
Why Pair
- Server-rendered web applications without a heavy frontend build chain.
- MVC routing with clear module/action conventions.
- ActiveRecord-style ORM with practical type casting and relation helpers.
- API tooling for CRUD resources and OpenAPI-oriented contracts.
- Native mobile helpers through
mobile/ios/PairMobileKitandmobile/android/PairMobileAndroid. - PairUI helpers for progressive enhancement.
- PWA, push and passkey helpers without forcing a SPA architecture.
- Runtime extensions for optional integrations.
- Installable package architecture for modules, templates, providers and custom package records.
- Useful defaults for timezone, logging, debugging and framework utilities.
- Small enough to understand, extend and maintain.
Well suited to AI-assisted development
Pair grew out of practical web application development and has a public repository history dating back to 2017. It was not designed around generated code; its advantage for AI-assisted development comes from the same qualities that help human maintainers understand it: a compact codebase, predictable component boundaries, limited hidden behavior and conventions that favor small, reviewable changes.
- A consistent component layout reduces the context needed to locate related code and nearby examples.
- Limited runtime dependencies and a server-rendered-first approach make application behavior easier to trace end to end.
- Pair v4 uses explicit input, response, page-state and API read-model contracts to reduce hidden assumptions.
- Focused automated tests and CI provide fast feedback across the supported PHP versions and native mobile helpers.
- Repository-level agent instructions document the architecture, coding conventions and patterns that should not be imported from heavier frameworks.
These properties do not make AI-generated changes automatically correct. They make proposed changes easier to constrain, inspect, test and review.
Core features
Routing and MVC
Default route format after the base path:
/<module>/<action>/<params...>
Example:
example.com/user/login
Typical legacy MVC module structure:
/modules/user/controller.php /modules/user/model.php /modules/user/viewLogin.php /modules/user/layouts/login.php
In Pair v4, legacy Pair\Core\Controller and Pair\Core\View remain available as migration bridges, but new modules should prefer explicit controllers and responses.
Docs: Router
ActiveRecord ORM
Pair maps PHP classes to database tables and supports practical ORM features such as:
- automatic casts for
int,bool,DateTime,floatandcsv - relation helpers
- query helpers
- cache-oriented access patterns
- database-backed CRUD resources
Docs: ActiveRecord
Pair v4 explicit 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 { public function defaultAction(): PageResponse { $state = new class ('Hello Pair v4') { public function __construct(public string $message) {} }; return $this->page('default', $state, 'User'); } }
Minimal layout example:
<main class="user-page"> <h1><?= htmlspecialchars($state->message, ENT_QUOTES, 'UTF-8') ?></h1> </main>
For reusable output contracts, Pair v4 prefers ReadModel objects built explicitly from persistence records.
API and OpenAPI tooling
Pair includes API helpers for CRUD-oriented resources and explicit response contracts. In Pair v4, OpenAPI generation for CRUD resources can use readModel contracts, so generated response schemas describe the public output model instead of leaking persistence classes.
Useful docs:
Log bar and debugging
Pair includes a built-in log bar for development and diagnostics:
- loaded objects
- memory usage
- timings
- application environment
- current Bootstrap/Bulma breakpoint when a matching UI framework is selected
- SQL traces
- backtraces
- custom debug messages
Frontend helpers
PairUI
PairUI is a dependency-free helper for progressive enhancement in server-rendered applications.
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
Available assets:
PairUI.jsPairPWA.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>
Form validation presets
Pair can share common form validation rules between PHP and JavaScript through FormValidationPreset, FormControl::preset() and PairValidation.js.
<script src="/assets/PairValidation.js" defer></script>
$form->emailAddress('email')->required(); $form->iban('ibanCode'); $form->webUrl('website'); $form->italianFiscalCode('fiscalCode'); $form->italianVatNumber('vatNumber');
Italy-specific presets use explicit Italian names or it.* preset identifiers, for example italianFiscalCode() and it.vat_number. International presets such as iban, email, url, bic, e164_phone, uuid, ip_address, mac_address, hex_color, ean13 and slug remain territory-neutral.
Important notes:
- Keep progressive enhancement.
- Service workers require HTTPS, except on localhost.
- Use a single service worker URL if you also enable push notifications.
Passkey quick start
Backend:
class ApiController extends \Pair\Api\PasskeyController {}
This enables:
POST /api/passkey/login/options
POST /api/passkey/login/verify
POST /api/passkey/register/options
POST /api/passkey/register/verify
GET /api/passkey/list
DELETE /api/passkey/revoke/{id}
Optional integrations
Pair includes optional support for services and runtime integrations such as:
- Amazon S3
- Amazon SES
- Telegram Bot API
- OneSignal
- Stripe
- Passkey/WebAuthn helpers
- Web push helpers
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)
Pair v4 tools
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.
Additional migration and design docs:
Upgrading
If you are upgrading a Pair v3 application to Pair v4, run the upgrader in dry-run mode first.
From a Pair application that has Pair installed as a dependency:
php vendor/viames/pair/scripts/upgrade-to-v4.php --dry-run php vendor/viames/pair/scripts/upgrade-to-v4.php --write
From inside the Pair repository itself:
composer run upgrade-to-v4 -- --dry-run composer run upgrade-to-v4 -- --write
The upgrader is conservative by design. It rewrites low-risk patterns automatically and reports legacy controller/view flows that still require manual migration.
Requirements
| Software | Minimum | Recommended | Notes |
|---|---|---|---|
| PHP | 8.4.1 | 8.5 | Required by Composer |
| Apache | 2.4 | 2.4+ | mod_rewrite recommended |
| MySQL | 8.0 | 8.0+ | utf8mb4, utf8mb4_unicode_ci, InnoDB |
| Composer | 2.x | Latest stable | Required for package installation |
Required PHP extensions:
curlintljsonmbstringpdopdo_mysql
Recommended or optional extensions:
fileinfofor reliable MIME detection in uploadsopensslfor Passkey/WebAuthn featuresredisfor Redis-backed integrationsxdebugfor development and debugging
Example project
Start from the boilerplate project to bootstrap a new application quickly:
https://github.com/viames/pair_boilerplate
Documentation
Main documentation lives in the Wiki:
https://github.com/viames/pair/wiki
Useful pages:
- Application
- Router
- Controller
- View
- ActiveRecord
- ApiExposable
- CrudController
- Form
- Collection
- Push notifications
- PairUI.js
- Configuration (.env)
- index.php
- .htaccess
- Classes folder
Development
Install dependencies:
composer install
Run tests:
composer test
Run the v4 benchmark harness:
composer run benchmark-v4
The benchmark harness 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
- Packagist: packagist.org/packages/viames/pair
Changelog
Version history is available in GitHub Releases:
https://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