PHPackages                             honey-odm/core - 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. honey-odm/core

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

honey-odm/core
==============

1.0.0.beta4(6mo ago)01401MITPHPPHP &gt;=8.4CI passing

Since Oct 13Pushed 3mo agoCompare

[ Source](https://github.com/bpolaszek/honey-odm)[ Packagist](https://packagist.org/packages/honey-odm/core)[ RSS](/packages/honey-odm-core/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (9)Dependencies (12)Versions (13)Used By (1)

🐝 Honey / ODM
=============

[](#-honey--odm)

A framework-agnostic, core foundation library for building modern Object Document Mappers (ODM) in PHP.

[![CI Workflow](https://github.com/bpolaszek/honey-odm/actions/workflows/ci-workflow.yml/badge.svg)](https://github.com/bpolaszek/honey-odm/actions/workflows/ci-workflow.yml)[![codecov](https://camo.githubusercontent.com/6e4a094d5224d5f006f9bf20ebe2e6c732b21303d35ef50d84f7db266e4c62cb/68747470733a2f2f636f6465636f762e696f2f67682f62706f6c61737a656b2f686f6e65792d6f646d2f6272616e63682f6d61696e2f67726170682f62616467652e737667)](https://codecov.io/gh/bpolaszek/honey-odm)

Overview
--------

[](#overview)

Honey ODM provides the essential interfaces, components, and patterns needed to build robust ODMs that can work with various data sources like REST APIs, NoSQL databases, or any custom storage backend. The library focuses on providing a solid foundation with built-in features like property transformers, event mechanisms, and identity management.

Key Features
------------

[](#key-features)

- **Generic Interface Design**: Core interfaces that can be implemented for any data source
- **Built-in Property Transformers**: Automatic data transformation between storage and PHP objects
- **Event System**: Comprehensive lifecycle events (pre/post persist, update, remove, load)
- **Identity Management**: Automatic object identity tracking and management
- **Unit of Work Pattern**: Efficient batch operations and change tracking
- **Trait-based Implementation**: Ready-to-use traits that simplify implementation

Requirements
------------

[](#requirements)

- PHP 8.4 or higher
- (Optional) PSR-14 Event Dispatcher implementation
- (Optional) PSR-11 Container implementation

Building your own ODM
---------------------

[](#building-your-own-odm)

Init your ODM project with Composer, then require Honey ODM core library:

```
composer require honey-odm/core
```

### Glossary

[](#glossary)

- **Class Metadata**: Metadata about a document class (e.g. endpoint / bucket / table name, whatever)
- **Property Metadata**: Metadata about a document property (e.g. name, transformer, is primary key, etc.)
- **Transport**: Handles communication with your data source
- **Object Manager**: Central component that orchestrates all ODM operations and events
- **Unit of Work**: Tracks changes and scheduled actions (insert, update, delete). The Unit of Work is destructed and recreated after each flush operation.
- **Object Repository**: Provides repository pattern methods for retrieving documents as objects.

### Essential Components

[](#essential-components)

To build an ODM using Honey, you need to extend these abstract classes and implement these core interfaces:

#### ClassMetadata

[](#classmetadata)

Class (attribute) that holds metadata information about your document classes, example:

```
namespace MyODM\Config;

use Attribute;
use Honey\ODM\Core\Config\ClassMetadata;

#[Attribute(Attribute::TARGET_CLASS)]
final class DocumentMetadata extends ClassMetadata
{
    public function __construct(
        public ?string $endpoint = null, // getClassMetadata($className) to get the ClassMetadata for the given class
    }
}
```

#### DocumentMapper

[](#documentmapper)

Service responsible for mapping documents (arrays) to objects and vice versa.

```
namespace MyODM\Mapper;

use Honey\ODM\Core\Mapper\DocumentMapperInterface;
use Honey\ODM\Core\Mapper\DocumentMapperTrait;

final readonly class DocumentMapper implements DocumentMapperInterface
{
    use DocumentMapperTrait; // objectManager;
        $classMetadataRegistry = $objectManager->classMetadataRegistry;
        $mapper = $objectManager->documentMapper;

        // Handle upserts (create/update)
        foreach ($unitOfWork->getPendingUpserts() as $object) {
            $classMetadata = $classMetadataRegistry->getClassMetadata($object::class);
            $context = new MappingContext($classMetadata, $objectManager, $object, []);
            $document = $mapper->objectToDocument($object, [], $context);

            $id = $classMetadataRegistry->getIdFromObject($object);
            $endpoint = $this->baseUrl . $classMetadata->endpoint;

            if ($id) {
                // Update existing
                $this->httpClient->put("{$endpoint}/{$id}", ['json' => $document]);
            } else {
                // Create new
                $response = $this->httpClient->post($endpoint, ['json' => $document]);
                $data = json_decode($response->getBody()->getContents(), true);
                // Set the generated ID back to the object
                $idProperty = $classMetadata->getIdPropertyMetadata()->reflection;
                $idProperty->setValue($object, $data['id']);
            }
        }

        // Handle deletes
        foreach ($unitOfWork->getPendingDeletes() as $object) {
            $classMetadata = $classMetadataRegistry->getClassMetadata($object::class);
            $id = $classMetadataRegistry->getIdFromObject($object);
            $endpoint = $this->baseUrl . $classMetadata->endpoint;

            $this->httpClient->delete("{$endpoint}/{$id}");
        }
    }

    public function retrieveDocuments(mixed $criteria): iterable
    {
        // Implementation depends on your API's query capabilities
        // This is a simplified example
        throw new LogicException('Query implementation depends on your specific API');
    }

    public function retrieveDocumentById(ClassMetadata $classMetadata, mixed $id): ?array
    {
        $endpoint = $this->baseUrl . $classMetadata->endpoint;

        try {
            $response = $this->httpClient->get("{$endpoint}/{$id}");
            return json_decode($response->getBody()->getContents(), true);
        } catch (RequestException $e) {
            if ($e->getResponse()?->getStatusCode() === 404) {
                return null;
            }
            throw $e;
        }
    }
}
```

### 4. Set Up the ODM

[](#4-set-up-the-odm)

```
namespace APp;

use RestBookODM\ObjectManager;
use GuzzleHttp\Client;
use Symfony\Component\EventDispatcher\EventDispatcher;

// Create HTTP client
$httpClient = new Client([
    'timeout' => 30,
    'headers' => [
        'Content-Type' => 'application/json',
        'Accept' => 'application/json',
    ],
]);

// Set up components
$transport = new RestTransport($httpClient, 'https://api.example.com');
$eventDispatcher = new EventDispatcher();
$classMetadataRegistry = new ClassMetadataRegistry(); // persist($book);
$objectManager->flush(); // Makes HTTP POST to /api/books

// Retrieve data
$foundBook = $objectManager->find(Book::class, $book->id); // Makes HTTP GET
```

Built-in Features
-----------------

[](#built-in-features)

### Property Transformers

[](#property-transformers)

The library includes several built-in transformers:

- **DateTimeImmutableTransformer**: Handles DateTime objects
- **RelationTransformer**: Manages object relationships
- **Custom transformers**: Implement `PropertyTransformerInterface`

### Event System

[](#event-system)

Listen to object lifecycle events:

```
use Honey\ODM\Core\Event\PrePersistEvent;

$eventDispatcher->addListener(PrePersistEvent::class, function (PrePersistEvent $event) {
    $object = $event->object;
    // Modify object before persistence
});
```

Available events:

- `PrePersistEvent` / `PostPersistEvent`
- `PreUpdateEvent` / `PostUpdateEvent`
- `PreRemoveEvent` / `PostRemoveEvent`
- `PostLoadEvent` (when an object is retrieved from the persistence layer)

### Identity Management

[](#identity-management)

Objects are automatically tracked and managed:

```
$book1 = $objectManager->find(Book::class, '123');
$book2 = $objectManager->find(Book::class, '123');

var_dump($book1 === $book2); // true - same instance returned
```

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

[](#contributing)

We welcome contributions! Here's how to get started:

### Development Setup

[](#development-setup)

1. Clone the repository:

```
git clone https://github.com/bpolaszek/honey-odm.git
cd honey-odm
```

2. Install dependencies:

```
composer install
```

3. Run checks:

```
composer ci:check
```

### Testing

[](#testing)

The library uses Pest for testing. Tests are located in the `tests/` directory:

- `tests/Unit/` - Unit tests
- `tests/Behavior/` - Behavioral tests
- `tests/Implementation/` - Example implementation (great for understanding usage patterns)

Run the full test suite:

```
composer tests:run
```

### Code Standards

[](#code-standards)

- Follow PSR-12 coding standards
- Use strict types (`declare(strict_types=1)`)
- Maintain 100% test coverage
- Use PHPStan level 9 for static analysis

### Submitting Changes

[](#submitting-changes)

1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Make your changes with tests
4. Ensure all checks pass (`composer ci:check`)
5. Commit your changes (`git commit -m 'Add amazing feature'`)
6. Push to the branch (`git push origin feature/amazing-feature`)
7. Open a Pull Request

### Reporting Issues

[](#reporting-issues)

Please use GitHub Issues to report bugs or request features. Include:

- PHP version
- Library version
- Clear description of the issue
- Code examples to reproduce the problem

Known Implementations
---------------------

[](#known-implementations)

- [honey-odm/meilisearch](https://github.com/bpolaszek/honey-meilisearch) - A Meilisearch ODM

License
-------

[](#license)

MIT.

###  Health Score

37

—

LowBetter than 83% of packages

Maintenance74

Regular maintenance activity

Popularity12

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity46

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% 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 ~13 days

Total

9

Last Release

112d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/acdd1a8ee0e657ddd06cf11f98a32100ef7121afb8aa270a5b295f5c29c038b3?d=identicon)[bpolaszek](/maintainers/bpolaszek)

---

Top Contributors

[![bpolaszek](https://avatars.githubusercontent.com/u/5569077?v=4)](https://github.com/bpolaszek "bpolaszek (16 commits)")

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/honey-odm-core/health.svg)

```
[![Health](https://phpackages.com/badges/honey-odm-core/health.svg)](https://phpackages.com/packages/honey-odm-core)
```

###  Alternatives

[robmorgan/phinx

Phinx makes it ridiculously easy to manage the database migrations for your PHP app.

4.5k46.2M405](/packages/robmorgan-phinx)[kimai/kimai

Kimai - Time Tracking

4.6k7.4k1](/packages/kimai-kimai)[patchlevel/event-sourcing

A lightweight but also all-inclusive event sourcing library with a focus on developer experience

198283.8k7](/packages/patchlevel-event-sourcing)[hyperf/database

A flexible database library.

202.8M257](/packages/hyperf-database)[tommyknocker/pdo-database-class

Framework-agnostic PHP database library with unified API for MySQL, MariaDB, PostgreSQL, SQLite, MSSQL, and Oracle. Query Builder, caching, sharding, window functions, CTEs, JSON, migrations, ActiveRecord, CLI tools, AI-powered analysis. Zero external dependencies.

845.7k](/packages/tommyknocker-pdo-database-class)[thewunder/corma

Convention-based Alternative ORM

3317.3k1](/packages/thewunder-corma)

PHPackages © 2026

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