PHPackages                             hostnet/entity-mutation-component - 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. [Utility &amp; Helpers](/categories/utility)
4. /
5. hostnet/entity-mutation-component

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

hostnet/entity-mutation-component
=================================

Listens to an event so mutations can be made

1.0.7(1y ago)3110.6k↓15.4%4MITPHPPHP ^7.3||^8.0CI passing

Since Aug 12Pushed 1y ago4 watchersCompare

[ Source](https://github.com/hostnet/entity-mutation-component)[ Packagist](https://packagist.org/packages/hostnet/entity-mutation-component)[ RSS](/packages/hostnet-entity-mutation-component/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (10)Dependencies (6)Versions (11)Used By (0)

README
======

[](#readme)

- [What is the Mutation Component?](#what-is-the-entity-mutation-component)
- [Requirements](#requirements)
- [Installation](#installation)

### Documentation

[](#documentation)

- [How does it work?](#how-does-it-work)
- [Setup](#setup)
    - [Registering the Events](#registering-the-events)
    - [Configuring the Entity](#configuring-the-entity)
    - [Creating the Mutation Entity](#creating-the-mutation-entity)
    - [What's Next?](#whats-next)

What is the Entity Mutation Component?
--------------------------------------

[](#what-is-the-entity-mutation-component)

The Entity Mutation Component is a library that utilizes the [Entity Tracker Component](https://github.com/hostnet/entity-tracker-component/) and lets you hook in to the entityChanged event.

This component lets you automatically store mutations based on two different strategies: copy current and copy previous. The first copies the current state into the mutation Entity and the latter will copy the previous state into the mutation Entity.

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

[](#requirements)

The Entity Mutation Component requires a minimum of php 7.3 and runs on Doctrine2. For specific requirements, please check [composer.json](../master/composer.json).

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

[](#installation)

Installing is pretty easy, this package is available on [packagist](https://packagist.org/packages/hostnet/entity-mutation-component). You can register the package locked to a major as we follow [Semantic Versioning 2.0.0](http://semver.org/).

#### Example

[](#example)

```
$ composer require hostnet/entity-mutation-component

```

Documentation
=============

[](#documentation-1)

How does it work?
-----------------

[](#how-does-it-work)

It works by putting the `@Mutation` annotation on your Entity and registering the listener on the entityChanged event, assuming you have already configured the [Entity Tracker Component](https://github.com/hostnet/entity-tracker-component/#setup).

For a usage example, follow the setup below.

Setup
-----

[](#setup)

- You have to add `@Mutation` to your Entity
- You have to create your Mutation Entity
- Optionally you can add the `MutationAwareInterface` if your Entity knows about its own mutations

#### Registering the events

[](#registering-the-events)

Here's an example of a very basic setup. Setting this up will be a lot easier if you use a framework that has a Dependency Injection Container.

It might look a bit complicated to set up, but it's pretty much setting up the tracker component for the most part. If you use it in a framework, it's recommended to create a framework specific configuration package for this to automate this away.

> Note: If you use Symfony, you can take a look at the [hostnet/entity-tracker-bundle](https://github.com/hostnet/entity-tracker-bundle). This bundle is designed to configure the services for you.

```
use Hostnet\Component\EntityMutation\Resolver\MutationResolver;
use Hostnet\Component\EntityTracker\Listener\EntityChangedListener;
use Hostnet\Component\EntityTracker\Provider\EntityAnnotationMetadataProvider;
use Hostnet\Component\EntityTracker\Provider\EntityMutationMetadataProvider;

/* @var $em \Doctrine\ORM\EntityManager */
$event_manager = $em->getEventManager();

// default doctrine annotation reader
$annotation_reader = new AnnotationReader();

// setup required providers
$annotation_metadata_provider = new EntityAnnotationMetadataProvider($annotation_reader);
$mutation_metadata_provider   = new EntityMutationMetadataProvider($annotation_reader);

// pre flush event listener that uses the @Mutation annotation
$entity_changed_listener = new EntityChangedListener(
    $annotation_metadata_provider,
    $mutation_metadata_provider
);

// the resolver is used to find the correct annotation, which
// fields are considered to be tracked and stored as mutation
// and which entity represents your Mutation entity.
$mutation_resolver = new MutationResolver($annotation_metadata_provider);

// creating the mutation listener
$mutation_listener = new MutationListener($mutation_resolver);

// register the events
$event_manager->addEventListener('prePersist', $entity_changed_listener);
$event_manager->addEventListener('preFlush', $entity_changed_listener);
$event_manager->addEventListener('entityChanged', $mutation_listener);
```

#### Configuring the Entity

[](#configuring-the-entity)

All we have to do now is put the `@Mutation` annotation on our Entity. The annotation has 2 options:

- strategy; This will determine if the current state or the previous state is stored in the Mutation
- class; the full namespace to your mutation class. By default it's the current class name suffixed with Mutation (i.e. `Acme\MyEntity` would be `Acme\MyEntityMutation` by default).

Additionally you can configure your entity to be MutationAware, this is optional however.

```
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\Mapping as ORM;
use Hostnet\Component\EntityMutation\Mutation;
use Hostnet\Component\EntityMutation\MutationAwareInterface;

/**
 * @ORM\Entity
 * @ORM\Table(name="users")
 * @Mutation(
 *     class    = "MyUserEntityMutation",
 *     strategy = "previous"
 * )
 * The above values are equal to the defaults. They are only
 * here to show how you can use them outside of this example
 */
class MyUserEntity implements MutationAwareInterface
{
    ...
    private $id;

    /**
     * @ORM\...
     */
    private $city;

    /**
     * @ORM\...
     */
    private $name;

    /**
     * @ORM\OneToMany...
     * @var ArrayCollection
     */
    private $mutations;

    public function setName($name) { ... }
    public function getName() { ... }

    public function addMutation($element)
    {
        $this->mutations->add($element);
    }

    public function getMutations()
    {
        return $this->mutations;
    }

    /**
     * Used to get the last mutation stored, you might want to change
     * it to return the one before that if your strategy is current.
     */
    public function getPreviousMutation()
    {
        $criteria = (new Criteria())
            ->orderBy(['id' => Criteria::DESC])
            ->setMaxResults(1);

        return $this->mutations->matching($criteria)->current() ? : null;
    }
}
```

#### Creating the Mutation Entity

[](#creating-the-mutation-entity)

The Mutation is an Entity itself. In the current version, the MutationResolver will only return the mutated fields if they are shared between the Entity and the EntityMutation. This is easily done by adding a trait that contains the shared fields. In this example, the only property that will be used to store a mutation, is `$name`.

The constructor is one of the few actual conventions you should follow in order to use the mutations. The first parameter is the current &amp; managed entity, where the original data is the previous state (as doctrine hydrated it the last time you retrieved it) and is unmanaged by doctrine.

This is done so you have full control over the what fields and how you want to store mutations. For instance, in some cases you might want to summarize or convert certain fields which would not be possible if this were done automatically without a complex system of data transformers.

> Note: The $original\_data is an unmanaged entity and should only be used for reading properties. Use the first parameter for joins.

```
use Doctrine\ORM\Mapping as ORM;

class MyUserEntityMutation
{
    ...

    /**
     * @ORM\ManyToOne(targetEntity="MyUserEntity", inversedBy="mutations")
     */
    private $user;

    /**
     * @ORM\...
     */
    private $name;

    public function setName($name) { ... }
    public function getName() { ... }

    public function __construct(MyUserEntity $user, MyUserEntity $original_data)
    {
        // link our user to the mutation
        $this->user = $user;

        // populate the mutation with data from the previous state
        $this->name = $original_data->getName();
    }
}
```

A fully [working example](test/Functional/Entity) can be found in our tests.

#### What's next?

[](#whats-next)

```
$my_user_entity->setName('Henk'); // was Hans before
$em->flush();
var_dump($my_user_entity->getPreviousMutation()); // shows the state it had with Hans
```

###  Health Score

47

—

FairBetter than 94% of packages

Maintenance42

Moderate activity, may be stable

Popularity36

Limited adoption so far

Community20

Small or concentrated contributor base

Maturity74

Established project with proven stability

 Bus Factor3

3 contributors hold 50%+ of commits

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 ~426 days

Recently: every ~776 days

Total

10

Last Release

461d ago

Major Versions

0.0.2 → 1.0.02014-09-09

PHP version history (4 changes)0.0.1PHP 5.\*, &gt;=5.4

1.0.1PHP 7.\*|5.\*,&gt;=5.4

1.0.2PHP 5.\*,&gt;=5.6||7.\*

1.0.4PHP ^7.3||^8.0

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/5468127?v=4)[Yannick de Lange](/maintainers/yannickl88)[@yannickl88](https://github.com/yannickl88)

![](https://www.gravatar.com/avatar/65433e1ef6edb2e8f96e18614b6618c84eed20ad0de6de0d0da36a9032ec7a18?d=identicon)[hostnet](/maintainers/hostnet)

---

Top Contributors

[![yannickl88](https://avatars.githubusercontent.com/u/5468127?v=4)](https://github.com/yannickl88 "yannickl88 (11 commits)")[![linaori](https://avatars.githubusercontent.com/u/1754678?v=4)](https://github.com/linaori "linaori (7 commits)")[![janlam7](https://avatars.githubusercontent.com/u/5459235?v=4)](https://github.com/janlam7 "janlam7 (6 commits)")[![nutama](https://avatars.githubusercontent.com/u/9001392?v=4)](https://github.com/nutama "nutama (6 commits)")[![nicoschoenmaker](https://avatars.githubusercontent.com/u/1469323?v=4)](https://github.com/nicoschoenmaker "nicoschoenmaker (5 commits)")[![stefanlenselink](https://avatars.githubusercontent.com/u/834562?v=4)](https://github.com/stefanlenselink "stefanlenselink (2 commits)")[![StijnKlopper2k](https://avatars.githubusercontent.com/u/198602351?v=4)](https://github.com/StijnKlopper2k "StijnKlopper2k (1 commits)")[![svandervlugt](https://avatars.githubusercontent.com/u/9334451?v=4)](https://github.com/svandervlugt "svandervlugt (1 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/hostnet-entity-mutation-component/health.svg)

```
[![Health](https://phpackages.com/badges/hostnet-entity-mutation-component/health.svg)](https://phpackages.com/packages/hostnet-entity-mutation-component)
```

###  Alternatives

[codefog/contao-haste

haste extension for Contao Open Source CMS

42650.8k139](/packages/codefog-contao-haste)[hostnet/entity-tracker-component

Provides an event when a Tracked entity changes

16158.1k4](/packages/hostnet-entity-tracker-component)[leapt/core-bundle

Symfony LeaptCoreBundle

2529.1k4](/packages/leapt-core-bundle)[kibatic/datagrid-bundle

Datagrid for Symfony

1418.3k](/packages/kibatic-datagrid-bundle)

PHPackages © 2026

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