PHPackages                             chamber-orchestra/metadata-bundle - 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. chamber-orchestra/metadata-bundle

ActiveSymfony-bundle[Database &amp; ORM](/categories/database)

chamber-orchestra/metadata-bundle
=================================

Symfony bundle for extending Doctrine ORM entities with custom attribute-driven metadata — cacheable mapping, embedded entity support, and autoconfigured drivers

v8.1.2(3w ago)04.3k↑12.5%5MITPHPPHP ^8.5CI passing

Since Jan 4Pushed 3w agoCompare

[ Source](https://github.com/chamber-orchestra/metadata-bundle)[ Packagist](https://packagist.org/packages/chamber-orchestra/metadata-bundle)[ Docs](https://github.com/chamber-orchestra/metadata-bundle)[ RSS](/packages/chamber-orchestra-metadata-bundle/feed)WikiDiscussions main Synced 2w ago

READMEChangelogDependencies (22)Versions (27)Used By (5)

[![PHP Composer](https://github.com/chamber-orchestra/metadata-bundle/actions/workflows/php.yml/badge.svg)](https://github.com/chamber-orchestra/metadata-bundle/actions/workflows/php.yml)[![PHP CS Fixer](https://camo.githubusercontent.com/38a469223430dcb2e92f6ade8149f377db8bda7d1b2c6fd04015fe6659faded0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f504850253230435325323046697865722d656e61626c65642d627269676874677265656e2e737667)](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer)[![Code Style: PER-CS](https://camo.githubusercontent.com/6ec1ce8cd297f8e9173b85f5c9b1831612578ea0e7fc8a55f3d33e1bdc049b57/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f64652532307374796c652d5045522d2d43532d626c75652e737667)](https://www.php-fig.org/per/coding-style/)[![Code Style: Symfony](https://camo.githubusercontent.com/4bdfc5c7cdcfe89ff8a5d1f818ff1c6b6e026546c788f6f88cf2dc28710985a5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f64652532307374796c652d53796d666f6e792d626c61636b2e737667)](https://symfony.com/doc/current/contributing/code/standards.html)[![PHPStan Level max](https://camo.githubusercontent.com/b6d441ad4fe8332cb16c72aa27f22cc685181dfd74ae34964afc92c6c1146b3c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6c6576656c2532306d61782d627269676874677265656e2e737667)](https://phpstan.org/)[![PHP 8.5](https://camo.githubusercontent.com/40afc499167234cbc9f48deebb4fac0b833dde32beb716e6737a26b359a4c0f9/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e352d3737374242342e737667)](https://www.php.net/)[![Symfony 8.0](https://camo.githubusercontent.com/daaa476b3cc456701380f7d0fbdc3bbe9983e89d3267f99870daa88aa719e181/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f53796d666f6e792d382e302d3030303030302e737667)](https://symfony.com/)[![Doctrine ORM 3](https://camo.githubusercontent.com/8c8b68c0a485baa4cd25005aa8e9bbe59ce922f1fe73068ee09a48302ada46f5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f446f637472696e652532304f524d2d332d6f72616e67652e737667)](https://www.doctrine-project.org/)[![Latest Stable Version](https://camo.githubusercontent.com/c6552fa364f093e1703fc65479d5fb436d9f52981efed7006a9c74f2d6f042ba/68747470733a2f2f706f7365722e707567782e6f72672f6368616d6265722d6f72636865737472612f6d657461646174612d62756e646c652f76)](https://packagist.org/packages/chamber-orchestra/metadata-bundle)[![License](https://camo.githubusercontent.com/b0758060f6b8d7665f437c5bb640e486f5989ba034c68e1f16412b88ffffaf9a/68747470733a2f2f706f7365722e707567782e6f72672f6368616d6265722d6f72636865737472612f6d657461646174612d62756e646c652f6c6963656e7365)](https://packagist.org/packages/chamber-orchestra/metadata-bundle)

ChamberOrchestra Metadata Bundle
================================

[](#chamberorchestra-metadata-bundle)

A Symfony bundle for extending Doctrine ORM entities with custom attribute-driven metadata. Define PHP attributes on your entities and let autoconfigured mapping drivers turn them into cacheable, serializable metadata — with full support for embedded classes and multiple entity managers.

Features
--------

[](#features)

- **PHP attribute-based mapping** — define custom metadata using native PHP 8 attributes on entity classes and properties
- **Cacheable metadata** — multi-level cache (PSR-6 + in-memory) with serialization support for production performance
- **Embedded entity support** — automatic recursive metadata resolution for Doctrine embeddables with lazy field initialization
- **Autoconfigured mapping drivers** — implement `MappingDriverInterface` and drivers are auto-tagged via Symfony DI
- **Doctrine event integration** — hooks into `loadClassMetadata` to load extension metadata alongside Doctrine's own metadata
- **Multiple EntityManager support** — cache isolation per EntityManager via `spl_object_id` scoping
- **Zero configuration** — install the bundle and start writing drivers; no YAML/XML configuration required

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

[](#installation)

```
composer require chamber-orchestra/metadata-bundle
```

Quick Start
-----------

[](#quick-start)

### 1. Define a Mapping Driver

[](#1-define-a-mapping-driver)

Create a mapping driver by extending `AbstractMappingDriver`. Override `getClassAttribute()` or `getPropertyAttribute()` to declare which PHP attributes your extension requires:

```
use ChamberOrchestra\MetadataBundle\Mapping\Driver\AbstractMappingDriver;
use ChamberOrchestra\MetadataBundle\Mapping\ExtensionMetadataInterface;

class TimestampableDriver extends AbstractMappingDriver
{
    protected function getClassAttribute(): string|null
    {
        return Timestampable::class;
    }

    public function loadMetadataForClass(ExtensionMetadataInterface $extensionMetadata): void
    {
        // Read attributes and populate your metadata configuration
    }
}
```

Drivers implementing `MappingDriverInterface` are automatically tagged and registered by the bundle.

### 2. Create a Metadata Factory

[](#2-create-a-metadata-factory)

Extend `AbstractExtensionMetadataFactory` to define how your extension metadata is created and loaded:

```
use ChamberOrchestra\MetadataBundle\Mapping\AbstractExtensionMetadataFactory;
use ChamberOrchestra\MetadataBundle\Mapping\ExtensionMetadataInterface;
use Doctrine\Persistence\Mapping\ClassMetadata;

class TimestampableMetadataFactory extends AbstractExtensionMetadataFactory
{
    protected function newClassMetadataInstance(ClassMetadata $metadata): ExtensionMetadataInterface
    {
        return new ExtensionMetadata($metadata);
    }

    protected function doLoadMetadata(ExtensionMetadataInterface $class): void
    {
        // Delegate to your mapping drivers
    }
}
```

### 3. React to Doctrine Events

[](#3-react-to-doctrine-events)

Use `AbstractDoctrineListener` to access extension metadata during Doctrine lifecycle events:

```
use ChamberOrchestra\MetadataBundle\EventSubscriber\AbstractDoctrineListener;
use Doctrine\Bundle\DoctrineBundle\Attribute\AsDoctrineListener;
use Doctrine\ORM\Event\PrePersistEventArgs;
use Doctrine\ORM\Events;

#[AsDoctrineListener(event: Events::prePersist)]
class TimestampableListener extends AbstractDoctrineListener
{
    public function prePersist(PrePersistEventArgs $args): void
    {
        foreach ($this->getScheduledEntityInsertions($args->getEntityManager(), TimestampableConfiguration::class) as $metadataArgs) {
            $metadataArgs->extensionMetadata->setFieldValue(
                $metadataArgs->entity,
                'createdAt',
                new \DateTimeImmutable()
            );
        }
    }
}
```

Architecture
------------

[](#architecture)

```
MetadataSubscriber (Doctrine loadClassMetadata event)
  └── MetadataReader
        └── AbstractExtensionMetadataFactory
              ├── MappingDriverInterface[] (attribute-based mapping drivers)
              ├── ExtensionMetadataInterface (per-entity extension metadata)
              │     ├── MetadataConfigurationInterface[] (per-driver configurations)
              │     └── Embedded metadata (recursive for embeddables)
              └── PSR-6 Cache (serialized metadata storage)

```

### Key Abstractions

[](#key-abstractions)

Class / InterfaceRole`MappingDriverInterface`Extension point — implement to define attribute-driven metadata`AbstractMappingDriver`Base driver with `AttributeReader` and `supports()` logic`MetadataConfigurationInterface`Stores field mappings; serializable for Doctrine cache`AbstractDoctrineListener`Base for Doctrine listeners that need extension metadata`MetadataArgs`DTO bundling EntityManager, metadata, configuration, and entityRequirements
------------

[](#requirements)

- PHP 8.5+
- Symfony 8.0
- Doctrine ORM 3.6+
- Doctrine Bundle 3.2+

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

[](#development)

```
composer install   # Install dependencies
composer test      # Run the test suite
```

License
-------

[](#license)

MIT

###  Health Score

53

—

FairBetter than 96% of packages

Maintenance95

Actively maintained with recent releases

Popularity24

Limited adoption so far

Community18

Small or concentrated contributor base

Maturity63

Established project with proven stability

 Bus Factor1

Top contributor holds 83.3% 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

Recently: every ~39 days

Total

16

Last Release

22d ago

PHP version history (2 changes)v8.0.1PHP ^8.4

v8.0.4PHP ^8.5

### Community

Maintainers

![](https://www.gravatar.com/avatar/44037eb1c8dc2c4fa9871ac213653f33e22a9348dcec7132df07cc71933f2a2e?d=identicon)[wtorsi](/maintainers/wtorsi)

---

Top Contributors

[![wtorsi](https://avatars.githubusercontent.com/u/2115840?v=4)](https://github.com/wtorsi "wtorsi (20 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (4 commits)")

---

Tags

doctrinedoctrine-extensionsdoctrine-ormembeddableentitymappingmetadataormphpphp-attributessymfonysymfony-bundlesymfonyormdoctrinemetadataentitymappingextensionSymfony Bundledoctrine-ormphp-attributesdoctrine-extensionsembeddable

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/chamber-orchestra-metadata-bundle/health.svg)

```
[![Health](https://phpackages.com/badges/chamber-orchestra-metadata-bundle/health.svg)](https://phpackages.com/packages/chamber-orchestra-metadata-bundle)
```

###  Alternatives

[2lenet/crudit-bundle

The easy like Crud'it Bundle.

1617.3k16](/packages/2lenet-crudit-bundle)[easycorp/easyadmin-bundle

Admin generator for Symfony applications

4.3k18.3M430](/packages/easycorp-easyadmin-bundle)[sylius/sylius

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

8.5k6.0M777](/packages/sylius-sylius)[rcsofttech/audit-trail-bundle

Enterprise-grade, high-performance Symfony audit trail bundle. Automatically track Doctrine entity changes with split-phase architecture, multiple transports (HTTP, Queue, Doctrine), and sensitive data masking.

12017.1k](/packages/rcsofttech-audit-trail-bundle)

PHPackages © 2026

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