PHPackages                             middag-io/framework - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. middag-io/framework

ActiveLibrary[Framework](/categories/framework)

middag-io/framework
===================

MIDDAG PHP Framework — DDD kernel, container, Inertia adapter, router, form engine, and domain abstractions

v1.8.0(1w ago)03.0k↑807.1%3Apache-2.0PHPPHP ^8.2CI passing

Since Jun 4Pushed 1w agoCompare

[ Source](https://github.com/middag-io/middag-php-framework)[ Packagist](https://packagist.org/packages/middag-io/framework)[ Docs](https://github.com/middag-io/middag-php-framework)[ RSS](/packages/middag-io-framework/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (10)Dependencies (294)Versions (30)Used By (3)

middag-io/framework
===================

[](#middag-ioframework)

**Symfony-grade DDD architecture that runs inside a Moodle or WordPress plugin, or standalone.**

[Documentation](https://docs.middag.dev) · [Where it runs](#where-it-runs) · [Professional services](#professional-services) · [GitHub](https://github.com/middag-io/middag-php-framework)

[![CI](https://github.com/middag-io/middag-php-framework/actions/workflows/ci.yml/badge.svg)](https://github.com/middag-io/middag-php-framework/actions/workflows/ci.yml) [![License: Apache 2.0](https://camo.githubusercontent.com/5b60841bea9e11d9d0b0950d690c9bc554e06385634056a7d5d62a15d1a4eabe/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4170616368655f322e302d626c75652e737667)](https://opensource.org/licenses/Apache-2.0) [![PHP](https://camo.githubusercontent.com/38db6e59e2b3b5169bd1aba5ff029b639e6246a3e64d07f8821c954a1202c3eb/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253545382e322d3737374242342e737667)](https://www.php.net/) [![PHPStan](https://camo.githubusercontent.com/2761aeebb3945f1ca4e4b0f156a71a3558c10dd6e3da83b1feb44f4d33013329/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6c6576656c253230362d627269676874677265656e2e737667)](https://phpstan.org/)

[![Packagist Version](https://camo.githubusercontent.com/f3ed38c63a77f49987da48f7f8c85e709d36487d81e64b96724c14a3f01c77ac/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6d69646461672d696f2f6672616d65776f726b2e737667)](https://packagist.org/packages/middag-io/framework) [![Packagist Downloads](https://camo.githubusercontent.com/cf3419bbbc2f26b884803ba2e44d3cbecac5944a7a3c83fcba6561678f9e5077/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6d69646461672d696f2f6672616d65776f726b2e737667)](https://packagist.org/packages/middag-io/framework)

About
-----

[](#about)

`middag-io/framework` is a platform-agnostic PHP framework for building business domains that do not depend on their host. You write controllers, forms, queries and services against contracts, then run the exact same code inside a Moodle plugin, a WordPress plugin, or as a standalone app by swapping a thin adapter.

> Your domain should not know, or care, where it runs.

Status: `1.x` — the API is still consolidating, so a minor release may carry a documented breaking change (see [`API-STABILITY.md`](API-STABILITY.md)). License: Apache-2.0.

Why middag-io/framework?
------------------------

[](#why-middag-ioframework)

Plugin code couples business logic straight to the host: `$DB`, `$CFG` and `mform` on Moodle, `$wpdb` on WordPress. That coupling is exactly what makes a plugin impossible to test without booting a full host, impossible to reuse on another platform, and fragile on every upgrade. This framework breaks the coupling, and gives you back four things:

- **Testable** — exercise your domain against an in-memory database, with no host running. The suite proves it.
- **Portable** — write the domain once; host it on Moodle, WordPress, or nothing at all, by changing one adapter.
- **Maintainable** — the domain outlives platform upgrades and migrations, because it never depended on the platform.
- **Familiar** — one coherent API over Symfony, PSR, Monolog and Inertia, not a new dialect to learn.

Built on giants
---------------

[](#built-on-giants)

We did not reinvent the wheel. Under the hood it is Symfony (dependency injection, HTTP kernel, routing, Messenger, Validator), plain PSR contracts, Monolog and Inertia, wrapped in a single host-agnostic API. Less of our code to carry bugs, battle-tested foundations underneath.

Installation
------------

[](#installation)

Requires PHP `^8.2` and the `curl`, `intl`, `json`, `mbstring` and `pdo` extensions. Runs standalone or behind a host adapter.

```
composer require middag-io/framework
```

Quick start
-----------

[](#quick-start)

A controller that loads your domain and renders an Inertia page: attribute routing, a domain service injected by the container, and not a single host API in sight.

```
use Middag\Framework\Http\Controller\AbstractController;
use Middag\Framework\Http\Inertia\InertiaAdapter;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;

final class CourseController extends AbstractController
{
    #[Route('/courses', name: 'courses')]
    public function index(CourseCatalog $catalog): Response
    {
        // CourseCatalog is your own domain service, injected by the container.
        // No $DB, no $CFG, no host — just your code, described in PHP.
        return InertiaAdapter::render('Courses/Index', [
            'courses' => $catalog->published(),
        ]);
    }
}
```

`CourseCatalog` is your service and `index()` stays plain PHP, so the exact same controller runs standalone, inside Moodle, or inside WordPress, by swapping the adapter.

And the proof of decoupling: the query layer runs with no host at all, over a plain PDO connection.

```
use Middag\Framework\Database\PdoConnectionAdapter;
use Middag\Framework\Persistence\Query\QueryBuilder;

$conn = new PdoConnectionAdapter(new PDO('sqlite::memory:')); // or a mysql:/pgsql: DSN

// The QueryBuilder is immutable. ::on() binds a connection, so the terminals execute.
$courses = QueryBuilder::on($conn, 'courses')
    ->where('published', true)   // equality shortcut
    ->orderBy('title')
    ->get();                     // array
```

What's inside
-------------

[](#whats-inside)

Generic plumbing, organised by concern (each concern owns its own `Contract/`):

ConcernWhat it does**Kernel**Symfony DI container booted from a `BootstrapInterface`, service auto-discovery, `AbstractModule`, `AbstractFacade`, and a per-instance WordPress-style `HookManager`.**Http**PSR-15 `HttpKernel`, `StandaloneKernel`, attribute routing (`#[Route]`), declarative auth (`#[Auth]` with rich `CapabilityRequirement` support), per-route middleware (`#[Middleware]`), `AbstractController` / `AbstractApiController`, and `AbstractFormRequest`.**Inertia**Full Inertia v3 protocol: lazy (`optional`), deferred (`defer`), merge (`merge` / `deepMerge`), partial reloads and asset versioning.**Form**`AbstractForm`, `FormValidator`, a set of field types (text, select, date, file, and more), and an Inertia renderer.**Persistence**An immutable `QueryBuilder`, an active-record `Model`, `AbstractRepository` / `AbstractMapper`, and `Page` pagination.**Database**`ConnectionAdapterInterface` with a default `PdoConnectionAdapter`, a SQL dialect layer, and a schema builder with migrations.**Bus**A command bus over Symfony Messenger (sync, plus async by transport routing), an `InMemoryTransport`, and a `CommandWorker`.**Logging**A Monolog-backed `LoggerFactory` per channel, with a `RotatingStreamHandler`.**Mail**A `MailerInterface` port with `Mail` / `Address` / `Attachment` value objects (inline `cid:` embeds included). The OSS default `NullMailer` discards; adapters map a `Mail` onto `email_to_user()` / `wp_mail()`.**Observability**An `ErrorReporterInterface` port (`NullErrorReporter` default, `SentryErrorReporter` behind a composer `suggest`) plus a `ProfileCollectorInterface` sink that gives bus, hook and query events a single profiling timeline.**Shared / Exception**DTOs, enums and utilities, plus a typed exception hierarchy mapped to HTTP status codes.Full API reference, guides and examples live at **[docs.middag.dev](https://docs.middag.dev)**.

Where it runs
-------------

[](#where-it-runs)

TargetHow**Standalone**Implement `Middag\Framework\Kernel\Contract\BootstrapInterface`, build the container with `ContainerFactory::build()`, and serve through `StandaloneKernel`.**Moodle**The OSS [`middag-io/moodle`](https://github.com/middag-io) adapter (`MoodleBootstrap` plus the bridge contracts).**WordPress**The OSS [`middag-io/wordpress`](https://github.com/middag-io) adapter (in build-out).An adapter is a thin layer that implements the bridge contracts (`BootstrapInterface`, `ConfigResolverInterface`, `ConnectionAdapterInterface`, `HostEventBridgeInterface`, `UserContextResolverInterface`, `TranslatorInterface`, `FormRendererInterface`). The framework ships a default OSS implementation of each, so it runs standalone with no adapter at all.

Open source and MIDDAG
----------------------

[](#open-source-and-middag)

The framework, the Moodle and WordPress adapters, and `middag-io/ui` are open source under Apache-2.0: the generic plumbing, free, forever.

The governed domain infrastructure that is genuinely hard to get right — reliable event delivery, async jobs with retry and audit, an EAV query engine, multi-tenancy, and licensing — is MIDDAG's proprietary product. It is built on top of this OSS and is opt-in, for when a domain outgrows the basics. The framework never imports the proprietary layer; the dependency only ever points downward.

Professional services
---------------------

[](#professional-services)

Adopting the framework, building a custom adapter, or migrating a legacy plugin to a testable domain? MIDDAG offers consulting and custom development. Reach us at  or visit [middag.io](https://middag.io) for more.

Development
-----------

[](#development)

```
composer test    # PHPUnit
composer check   # PHPStan (level 6) + PHP-CS-Fixer + Rector, all dry-run
composer fix     # auto-fix style and Rector (composer fix:all re-settles formatting afterwards)
```

Git hooks are wired automatically on install; the `commit-msg` hook enforces [Conventional Commits](https://www.conventionalcommits.org/), and releases are cut by [release-please](https://github.com/googleapis/release-please).

Contributing
------------

[](#contributing)

See [`CONTRIBUTING.md`](CONTRIBUTING.md) for the workflow, coding standards and quality pipeline. Please also read the [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md). Found a security issue? Follow [`SECURITY.md`](SECURITY.md).

Building on the framework? [`API-STABILITY.md`](API-STABILITY.md) defines the `@api` public surface, the `1.x` versioning policy (breaking changes may land in minors, always flagged in the changelog), and the host-neutral contracts frozen for the whole `1.x` line.

License
-------

[](#license)

Licensed under the Apache License, Version 2.0. See [`LICENSE`](LICENSE). Copyright 2026 MIDDAG.

###  Health Score

51

—

FairBetter than 95% of packages

Maintenance98

Actively maintained with recent releases

Popularity24

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity57

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 86.2% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1 days

Total

27

Last Release

9d ago

Major Versions

v0.11.3 → v1.0.02026-06-27

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/6410303?v=4)[Michael Douglas Meneses de Souza](/maintainers/michaelmeneses)[@michaelmeneses](https://github.com/michaelmeneses)

---

Top Contributors

[![michaelmeneses](https://avatars.githubusercontent.com/u/6410303?v=4)](https://github.com/michaelmeneses "michaelmeneses (168 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (27 commits)")

---

Tags

containerframeworkwordpressroutermoodlepsr-15inertiastandalonekerneldddform-engine

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Rector

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/middag-io-framework/health.svg)

```
[![Health](https://phpackages.com/badges/middag-io-framework/health.svg)](https://phpackages.com/packages/middag-io-framework)
```

###  Alternatives

[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

585.6M600](/packages/shopware-core)[shopware/platform

The Shopware e-commerce core

3.4k1.5M3](/packages/shopware-platform)[contao/core-bundle

Contao Open Source CMS

1231.6M2.8k](/packages/contao-core-bundle)[drupal/core-recommended

Locked core dependencies; require this project INSTEAD OF drupal/core.

6942.5M425](/packages/drupal-core-recommended)[sulu/sulu

Core framework that implements the functionality of the Sulu content management system

1.3k1.4M215](/packages/sulu-sulu)[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.5k5.9M754](/packages/sylius-sylius)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
