Search by

michel / paper-orm

F.Michel

PaperORM is a lightweight Object-Relational Mapping (ORM) library

Package info

github.com/michelphp/paper-orm

pkg:composer/michel/paper-orm

Statistics

Installs: 12

Dependents: 1

Suggesters: 0

Stars: 0

Open Issues: 0

0.1.2-alpha 2026-10-28 11:49 UTC

This package is auto-updated.

Last update: 2026-10-28 12:46:52 UTC


README

The ORM that does what you wrote, and nothing else.

Map your entities with attributes, query them through repositories, migrate your schema. No lazy loading, no cascade, no transaction you did not open. Every query runs because you asked for it.

PHP 8.2+ 路 SQLite 路 MariaDB / MySQL 路 Symfony bundle

馃摉 Documentation 路 Website

Install

composer require michel/paper-orm          # any PHP project
composer require michel/paper-orm-bundle   # Symfony

Quick start

use Michel\PaperORM\EntityManager;
use Michel\PaperORM\PaperConfiguration;

$em = EntityManager::createFromConfig(
    PaperConfiguration::fromDsn('sqlite:///var/data/app.sqlite')
);
use Michel\PaperORM\Entity\EntityInterface;
use Michel\PaperORM\Mapping\Entity;
use Michel\PaperORM\Mapping\Column\{PrimaryKeyColumn, StringColumn, BoolColumn};

#[Entity(table: 'user')]
class User implements EntityInterface
{
    #[PrimaryKeyColumn]
    private ?int $id = null;

    #[StringColumn]
    private ?string $email = null;

    #[BoolColumn(name: 'is_active')]
    private bool $active = true;

    public function getPrimaryKeyValue(): ?int { return $this->id; }

    // getters and setters...
}
$em->persist((new User())->setEmail('jane@example.com'));
$em->flush();

$users = $em->getRepository(User::class)
    ->findBy(['active' => true])
    ->orderBy('email')
    ->limit(20)
    ->toObject();            // User[]

Why PaperORM

No surprise query No lazy loading: a relation is loaded with with() or has(), in the same query. Nothing runs when you read a property.
Paginate one-to-many limit(10) returns 10 users, even when each brings 50 posts in the same join. Filter and sort on relations, the page stays right.
Your transactions flush() never opens a transaction behind your back.
Migrations as SQL paper:migration:diff writes a plain .sql file you can read; paper:migration:migrate runs it.
Small and fast About 21,000 lines of PHP with its dependencies, against about 171,000 for Doctrine ORM. Faster than or level with Doctrine on every scenario of the bundled benchmark.

What PaperORM will never do

lazy-load a relation 路 cascade a persist or a delete 路 open a transaction for you 路 invent a query language 路 query when you read a property 路 require a framework

Documentation

The documentation covers configuration, entities and relations, migrations, persistence, generated values, repositories, pagination, the query builder, transactions, events, the registry and the Symfony bundle.

Status

PaperORM is in alpha: the API may still change between 0.x versions. Bug reports and ideas are welcome in the issues.

License

MPL-2.0