PHPackages                             jpi/orm - 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. [Database &amp; ORM](/categories/database)
4. /
5. jpi/orm

ActiveLibrary[Database &amp; ORM](/categories/database)

jpi/orm
=======

Simple &amp; lightweight ORM

v2.5.0(2mo ago)01.3k↓88.9%[2 issues](https://github.com/jahidulpabelislam/orm/issues)GPL-3.0-onlyPHPPHP ^8.0CI passing

Since May 29Pushed 2mo ago1 watchersCompare

[ Source](https://github.com/jahidulpabelislam/orm)[ Packagist](https://packagist.org/packages/jpi/orm)[ RSS](/packages/jpi-orm/feed)WikiDiscussions 2.x Synced 1w ago

READMEChangelog (10)Dependencies (5)Versions (36)Used By (0)

ORM
===

[](#orm)

[![CodeFactor](https://camo.githubusercontent.com/c34b4da49638afcf18155c3301c0bf99dc52ce41d9442a27f9b052e9fceb7939/68747470733a2f2f7777772e636f6465666163746f722e696f2f7265706f7369746f72792f6769746875622f6a61686964756c706162656c69736c616d2f6f726d2f6261646765)](https://www.codefactor.io/repository/github/jahidulpabelislam/orm)[![Latest Stable Version](https://camo.githubusercontent.com/3f46a651b3d588c20063b9ad2560301898c3c2f204fb32d5b60fcdd7c4bc8d49/68747470733a2f2f706f7365722e707567782e6f72672f6a70692f6f726d2f762f737461626c65)](https://packagist.org/packages/jpi/orm)[![Total Downloads](https://camo.githubusercontent.com/8169293402dbc67ec5d40d3476e43c0efdf672095b1721c02df0fc6bd1b48c18/68747470733a2f2f706f7365722e707567782e6f72672f6a70692f6f726d2f646f776e6c6f616473)](https://packagist.org/packages/jpi/orm)[![Latest Unstable Version](https://camo.githubusercontent.com/90b5e9af6a4539740c9d40a2b2fed5f8936a623f3b74d01a40414e3db11fcb55/68747470733a2f2f706f7365722e707567782e6f72672f6a70692f6f726d2f762f756e737461626c65)](https://packagist.org/packages/jpi/orm)[![License](https://camo.githubusercontent.com/c85e020f0d373bf46ef145c4f0b6ca9cf30971f1c8919bcc68528a07554a98fb/68747470733a2f2f706f7365722e707567782e6f72672f6a70692f6f726d2f6c6963656e7365)](https://packagist.org/packages/jpi/orm)[![GitHub last commit (branch)](https://camo.githubusercontent.com/01965a581820c3b36cd41a77ad51eb7abf32c8810d6bf1014b16ce97302bae73/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6173742d636f6d6d69742f6a61686964756c706162656c69736c616d2f6f726d2f322e782e7376673f6c6162656c3d6c6173742532306163746976697479)](https://camo.githubusercontent.com/01965a581820c3b36cd41a77ad51eb7abf32c8810d6bf1014b16ce97302bae73/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6173742d636f6d6d69742f6a61686964756c706162656c69736c616d2f6f726d2f322e782e7376673f6c6162656c3d6c6173742532306163746976697479)

A super simple &amp; lightweight ORM following the active record pattern.

This has been kept very simple stupid (KISS), with minimal validation (PHP type errors only) to reduce complexity in the library and maximize performance for consumer developers. Therefore, please make sure to add your own validation if using user inputs in any database queries.

Features
--------

[](#features)

- Easy to configure for your project's entities
- Supporting scalar types, array, and date/time and relationships `Many-to-One`, `One-to-Many` and `One-to-One`
- Fluent, chainable API for CRUD operations, using integrated query builder from [jpi/query](https://packagist.org/packages/jpi/query)

Dependencies
------------

[](#dependencies)

- PHP 8.0+
- Composer
- PHP PDO
- MySQL 5+
- [jpi/database](https://packagist.org/packages/jpi/database) v2
- [jpi/query](https://packagist.org/packages/jpi/query) v2

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

[](#installation)

Use [Composer](https://getcomposer.org/)

```
$ composer require jpi/orm
```

### Properties and Methods for Setup

[](#properties-and-methods-for-setup)

You will need to extend `\JPI\ORM\Entity` and then define the following:

#### `getDatabase(): \JPI\Database`

[](#getdatabase-jpidatabase)

This method must be implemented to provide the database connection for this entity. `\JPI\Database` is just an extension of `PDO` - you can find out more [here](https://packagist.org/packages/jpi/database).

#### `$table: string`

[](#table-string)

The database table name for this entity.

#### `$dataMapping: array`

[](#datamapping-array)

This array defines the structure of your entity and maps to your database columns. Each key is a column name and the value is an array with:

- `type` (required): One of: `string`, `int`, `float`, `array`, `date`, `date_time`, `belongs_to`, `has_one`, `has_many`
- `default_value`
- `separator`: The separator for `array` type columns when stored as delimited strings (defaults to `","`)
- `entity`: The related entity class name (required for relationship types)
- `column`
    - The database column behind this for `belongs_to` type (defaults to `{key}_id`)
    - The key in related entity for `has_many` &amp; `has_one` types that links back to this
- `cascade_delete`: Whether to delete related entities when this entity is deleted (for `has_one` and `has_many` types)
- `cascade_clone`: Whether to clone related entities when this entity is cloned via `clone` - essentially creates new records with same data, else it sets to null/empty (for `has_one` and `has_many` types)

```
protected static array $dataMapping = [
    "name" => [
        "type" => "string",
    ],
    "sku" => [
        "type" => "string",
    ],
    "price" => [
        "type" => "float",
        "default_value" => 0.00,
    ],
    "categories" => [
        "type" => "array",
        "separator" => ",", // Optional, defaults to ","
    ],
    "created_at" => [
        "type" => "date_time",
    ],
];
```

#### `$columnPrefix: string` - optional

[](#columnprefix-string---optional)

Some database designers like to prefix their table columns. For example, the `products` table might have columns like `product_id` &amp; `product_name` instead of `id` &amp; `name`. Set this property to add that prefix automatically.

Note: the first underscore is required.

#### `$defaultOrderByColumn: string` - optional

[](#defaultorderbycolumn-string---optional)

The default column to order results by when selecting records and haven't specified an order. Default is `id`.

#### `$defaultOrderByASC: bool` - optional

[](#defaultorderbyasc-bool---optional)

Whether the default ordering should be ascending. Default is `true`.

### Complete Example

[](#complete-example)

```
...
class Product extends \JPI\ORM\Entity {

    protected static string $table = "products";

    protected static array $dataMapping = [
        "name" => [
            "type" => "string",
        ],
        "sku" => [
            "type" => "string",
        ],
        "price" => [
            "type" => "float",
        ],
        "stock" => [
            "type" => "int",
        ],
        "created_at" => [
            "type" => "date_time",
        ],
    ];

    public static function getDatabase(): \JPI\Database {
        return new \JPI\Database("mysql:host=localhost;dbname=shop", "username", "password");
    }

    ...
}
```

Relationships
-------------

[](#relationships)

The ORM supports three types of relationships:

#### `belongs_to` - Many-to-One

[](#belongs_to---many-to-one)

```
class Order extends Entity {
    ...
    protected static array $dataMapping = [
        ...
        "customer" => [
            "type" => "belongs_to",
            "entity" => Customer::class,
            "column" => "customer", // Defaults to "customer_id" if not specified
        ],
        ...
    ];
    ...
}

$order = Order::getById(1);
$customer = $order->customer; // Lazy loads the Customer entity
```

#### `has_many` - One-to-Many

[](#has_many---one-to-many)

```
class Order extends Entity {
    ...
    protected static array $dataMapping = [
        ...
        "items" => [
            "type" => "has_many",
            "entity" => OrderItem::class,
            "column" => "order", // The key in OrderItem that links back
            "cascade_delete" => true,
        ],
        ...
    ];
    ...
}

$order = Order::getById(1);
$items = $order->items; // Lazy loads a Collection of OrderItem entities
```

#### `has_one` - One-to-One

[](#has_one---one-to-one)

```
class Order extends Entity {
    ...
    protected static array $dataMapping = [
        ...
        "payment" => [
            "type" => "has_one",
            "entity" => Payment::class,
            "column" => "order",
            "cascade_delete" => true,
        ],
        ...
    ];
    ...
}

$order = Order::getById(1);
$payment = $order->payment; // Lazy loads the Payment entity
```

Usage
-----

[](#usage)

### Retrieving Entities

[](#retrieving-entities)

**`getById(int $id): ?static`** - Get an entity by its ID.

**`newQuery(): QueryBuilder`** - Get a query builder instance for advanced queries. See [Query Builder](#query-builder) section for examples.

### Accessing Entity Data

[](#accessing-entity-data)

You can get and set entity values using simple property access, these are the keys from `$dataMapping`. When setting the value must be value for the type defined or null.

### Creating and Saving Entities

[](#creating-and-saving-entities)

**`factory(?array $data = null): static`** - Create a new entity instance, and optionally set initial data in one call.

**`insert(array $data): static`** - Create and save an entity in one call.

**`save(): bool`** - Save (insert or update) the entity to the database.

### Deleting Entities

[](#deleting-entities)

**`delete(): bool`** - Delete the entity from the database.

### Utility Methods

[](#utility-methods)

**`isLoaded(): bool`** - Check if the entity has been loaded from or saved to the database.

**`isDeleted(): bool`** - Check if the entity has been deleted.

**`toArray(): array`** - Convert the entity to an array.

**`reload(): void`** - Reload the entity from the database.

Query Builder
-------------

[](#query-builder)

The query builder (accessed via `newQuery()`) provides a fluent interface for building database queries. It uses `\JPI\Database\Query\Builder` from [jpi/query](https://packagist.org/packages/jpi/query), see documentation there for full details on available query methods.

### Eager Loading

[](#eager-loading)

To avoid N+1 query problems, you can eager load relationships using the `with()` method:

```
// Eager load a single relationship
$orders = Order::newQuery()->with("customer")->select();

// Eager load multiple relationships
$orders = Order::newQuery()->with("customer", "items")->select();

// Eager load nested relationships
$orders = Order::newQuery()->with("customer.address")->select();

// Combine with other query methods
$orders = Order::newQuery()
    ->where("status", "=", "completed")
    ->orderBy("created_at", false)
    ->with("customer", "items")
    ->select();
```

Without eager loading, accessing relationships causes a separate query for each entity (N+1 problem). With eager loading, all related entities are fetched in a single optimized query.

### Lazy Eager Loading

[](#lazy-eager-loading)

If you already have a collection of entities and later need to load relationships, use the `load()` method:

```
// Get orders without relationships
$orders = Order::newQuery()->where("status", "=", "completed")->select();

// Later, load relationships on the collection
$orders->load("customer");

// Or load multiple relationships
$orders->load("customer", "items");

// Nested relationships work too
$orders->load("customer.address");
```

This is useful when you receive a collection from another part of your application and need to load relationships efficiently. Like `with()`, it prevents N+1 query problems by batching relationship queries instead of loading them one at a time.

Support
-------

[](#support)

If you found this library interesting or useful please spread the word about this library: share on your socials, star on GitHub, etc.

If you find any issues or have any feature requests, you can open a [issue](https://github.com/jahidulpabelislam/orm/issues) or email [me @ jahidulpabelislam.com](mailto:me@jahidulpabelislam.com) 😏.

Authors
-------

[](#authors)

- [Jahidul Pabel Islam](https://jahidulpabelislam.com/) [](mailto:me@jahidulpabelislam.com)

Licence
-------

[](#licence)

This module is licensed under the General Public Licence - see the [licence](LICENSE.md) file for details.

###  Health Score

46

—

FairBetter than 93% of packages

Maintenance83

Actively maintained with recent releases

Popularity14

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity65

Established project with proven stability

 Bus Factor1

Top contributor holds 94.6% 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 ~39 days

Recently: every ~10 days

Total

36

Last Release

85d ago

Major Versions

v1.1.3 → v2.0.0-beta.12024-05-03

PHP version history (3 changes)v1.0.0PHP ^7.1

v1.1.1PHP ^7.1 || ^8.0

v2.0.0-beta.1PHP ^8.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/3eb53275639d93b5fdae3b835527fdb958dbc1214e58a97d10fa50fe66a836cd?d=identicon)[jahidulpabelislam](/maintainers/jahidulpabelislam)

---

Top Contributors

[![jahidulpabelislam](https://avatars.githubusercontent.com/u/15434150?v=4)](https://github.com/jahidulpabelislam "jahidulpabelislam (140 commits)")[![Copilot](https://avatars.githubusercontent.com/in/1143301?v=4)](https://github.com/Copilot "Copilot (8 commits)")

---

Tags

databaseentitymodelormphpdatabaseormmysqlsqlmodelqueryentitycrudactive-recordRelationships

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/jpi-orm/health.svg)

```
[![Health](https://phpackages.com/badges/jpi-orm/health.svg)](https://phpackages.com/packages/jpi-orm)
```

###  Alternatives

[opis/database

A database abstraction layer over PDO, that provides a powerful and intuitive query builder, bundled with an easy to use schema builder

10184.2k3](/packages/opis-database)

PHPackages © 2026

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