PHPackages                             jasny/entity - 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. jasny/entity

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

jasny/entity
============

Object representation for stateful entities

v0.2.0(7y ago)2441MITPHPPHP &gt;=7.2.0

Since Apr 27Pushed 6y agoCompare

[ Source](https://github.com/jasny/entity)[ Packagist](https://packagist.org/packages/jasny/entity)[ Docs](http://jasny.github.com/entity)[ RSS](/packages/jasny-entity/feed)WikiDiscussions master Synced 4d ago

READMEChangelog (2)Dependencies (7)Versions (3)Used By (0)

Jasny Entity
============

[](#jasny-entity)

[![Build Status](https://camo.githubusercontent.com/0907e0eaf13ce5ac7d4cad0298b575db3688a99ec8630f308da5b9595b51f495/68747470733a2f2f7472617669732d63692e6f72672f6a61736e792f656e746974792e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/jasny/entity)[![Scrutinizer Code Quality](https://camo.githubusercontent.com/528cfe52349a2648f49ad5cafde5acb87a1a01bac905aa40789ff33e2f9011c8/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f6a61736e792f656e746974792f6261646765732f7175616c6974792d73636f72652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/jasny/entity/?branch=master)[![Code Coverage](https://camo.githubusercontent.com/a9d1f6601ee6c0e77818f51f24091097331ba98bd060f4ef4b17d66029073036/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f6a61736e792f656e746974792f6261646765732f636f7665726167652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/jasny/entity/?branch=master)[![Packagist Stable Version](https://camo.githubusercontent.com/b2e6f4dbbc2a2aac9257ca01aba14a4f02351a8cee57e81ffb7415a6a084695c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6a61736e792f656e746974792e737667)](https://packagist.org/packages/jasny/entity)[![Packagist License](https://camo.githubusercontent.com/102971d0fafe4eed526eb87d1b77724aa4e42a667a892120c11e65c680ba1a0c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6a61736e792f656e746974792e737667)](https://packagist.org/packages/jasny/entity)

An entity is a "thing" you want to represent in a database or other data stores. It can be a new article on your blog, a user in your message board or a permission in your rights management system.

The properties of an entity object is a representation of persisted data.

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

[](#installation)

```
composer require jasny/entity

```

Usage
-----

[](#usage)

```
namespace App;

use Jasny\Entity\IdentifiableEntityInterface;
use Jasny\Entity\IdentifiableEntityTraits;

/**
 * A user in our system
 */
class User extends AbstractIdentifiableEntity
{
    /** @var string */
    public $id;

    /** @var string */
    public $name;

    /** @var string */
    public $email;

    /** @var string */
    public $password_hash;
}
```

A quick and dirty script to create and output the JSON of a `User` entity could be

```
use App\User;
use Jasny\Entity\Event;

$data = $db->prepare("SELECT * FROM user WHERE id = ?")->execute($id)->fetch(PDO::FETCH_ASSOC);
$user = User::fromData($data);

$user->addEventListener(function(Event\ToJson $event): void {
    $data = $event->getPayload();
    unset($data['password_hash']);

    $event->setPaypload($data);
});

header('Content-Type: application\json');
echo json_serialize($user);
```

> *In this example you could just as well json serialize the data directly. The layer helps in adding abstraction to applications that are beyond simple scripts.*

Documentation
-------------

[](#documentation)

### Basic entity

[](#basic-entity)

The `Entity` interface defines the methods all entities need to implement. To implement an entity you may extend the `AbstractBasicEntity` base class. Alternatively you can use the [traits](#traits) of this library.

It's recommended to define properties as public, however only use them to get values and not to set. For setting values use the `set()` method. This isn't enforced at runtime, but may be checked by a static code analyser like PHPStan.

```
class Color extends AbstractBasicEntity
{
    /** @var int */
    public $red;

    /** @var int */
    public $green;

    /** @var int */
    public $blue;
}
```

### Identifiable entity

[](#identifiable-entity)

If an entity has a unique identifier, the class should implement `IdentifiableEntity`.

```
class User extends AbstractIdentifiableEntity
{
    /** @var int */
    public $id;

    /** @var string */
    public $name;

    /** @var string */
    public $email;

    /** @var string */
    public $password_hash;
}
```

It's assumed you're using property `id` as a surrogate key. If you're using a differently property, make sure to overwrite the static `getIdProperty()` method.

```
class Invoice extends AbstractIdentifiableEntity
{
    /** @var string */
    public $number;

    // ...

    protected static function getIdProperty(): string
    {
        return 'number';
    }
}
```

### Dynamic entity

[](#dynamic-entity)

By default entities should only have the properties that are specified by the class. The `set()` method will ignore all values that don't correspond with any property. If for some reason additional properties are added, the `toAssoc()`and `jsonSerialize()` methods, also ignore properties that aren't defined in the class.

In some cases an entity might be dynamic; it can have properties that are added at runtime. Some data stores like `MongoDB` have dynamic schemas, which don't have to be defined at forehand, to support this.

To indicate that an entity may have dynamic properties it should implement the `DynamicEntity` interface.

```
class User extends AbstractIdentifiableEntity implements DynamicEntity
{
    // ...
}
```

### New entity

[](#new-entity)

Using the `new` keyword is reserved for creating a new entity.

```
$user = new User(); // This represents a new user in the system
```

If you set the identified (`id` property) of a new entity, it will either overwrite it or throw an duplicate id error, depending on the data storage implementation. However it will (or rather should) not update the existing record.

The `isNew()` method will tell if it's a new user or if it's loaded from data.

### Existing entity

[](#existing-entity)

When the data of an entity is fetched, the static `fromData()` method is used to create the entity.

```
$data = $db->prepare("SELECT * FROM user WHERE id = ?")->execute($id)->fetch(PDO::FETCH_ASSOC);
$user = User::fromData($data);
```

The `fromData()` method sets the properties of the entity object, *before* calling the constructor.

##### var\_export

[](#var_export)

The `__set_state()` method is set as alias of `fromData()`, allowing entities to be serialized via [`var_export`](https://php.net/var_export) and stored as PHP script. Other libraries like [Jasny Typecast](https://github.com/jasny/typecast), rely on the `__set_state()` method as well.

### Set values

[](#set-values)

The `set()` method is a a helper function for setting all the properties from an array.

```
$foo = new Foo();
$foo->set('answer', 42);
$foo->set(['red' => 10, 'green' => 20, 'blue' => 30]);
```

It can be use as [fluent interface](http://en.wikipedia.org/wiki/Fluent_interface).

```
$adventure = (new Adventure)
  ->set('destination', 'unknown')
  ->set('duration', '1 year')
  ->go();
```

The `set()` method triggers 2 events; [`BeforeSet`](#entity-events) and [`AfterSet`](#entity-events).

### Same entities

[](#same-entities)

Check if two entities are the same using the `is()` method which returns a boolean. The method always returns `true` in case the objects are the same object (similar to `===`).

For identifiable objects, the method will also return `true` is the entity class and the `id` value are the same. The value of other properties are disregarded.

### Cast to associative array

[](#cast-to-associative-array)

Cast an entity to an associative array with the `toAssoc()` method. By default this method will return the values of all public properties.

```
$data = $user->toAssoc();
```

The [`ToAssoc`](#entity-events) event is available to modify the result of this method. The library comes with the `ToAssocRecursive` event listener, which will also turn child entities into associative arrays.

```
$user->addEventListener(function(Event\ToAssoc $event): void {
    $assoc = $event->getPayload();

    if (isset($assoc['password'])) {
        $assoc['password_hashed'] = password_hash($assoc['password'], PASSWORD_DEFAULT);
        unset($assoc['password_hashed']);
    }

    $event->setPayload($assoc);
});
```

> *The `toAssoc()` method can be used in farious places. It's not recommended to create event listeners to handle a specific use case. Instead create a new type of event for that specific use.*

### Cast to JSON

[](#cast-to-json)

Entities must implement `JsonSerializable`, meaning they can be casted to JSON via [`json_encode()`](https://php.net/json_encode). By default, the result is an object with all the public properties of the entity.

The `jsonSerialize` method can be overwritten in the entity class. Alternatively the [`ToJson`](#entity-events) event can be used to modify the result before it's serialized to a json string.

```
$user->addEventListener(function(Event\ToJson $event): void {
    $assoc = $event->getPayload();
    unset($assoc['password_hashed']);

    $event->setPayload($assoc);
});
```

The library contains the `JsonCast` event listener that will convert `DateTime` objects to a date string and will convert any (child) object that implements `JsonSerializable`.

### Persisting entities

[](#persisting-entities)

This library **does not** have any methods for saving entities into persistent storage (like a database).

It recommended to implement data gateway services for this (and not adopt Active Record pattern).

```
class UserGateway
{
    /** @var \PDO */
    protected $db;

    public function __construct(\PDO $db)
    {
        $this->db = $db;
    }

    public function load(string $id): User
    {
        $data = $db->prepare("SELECT * FROM user WHERE id = ?")->execute($id)->fetch(PDO::FETCH_ASSOC);

        if ($data === null) {
            throw new RuntimeException("User `$id` not found");
        }

        return User::fromData($data);
    }

    public function save(User $user): void
    {
        $data = $user->toAssoc();

        $columns = join(', ', array_keys($data));             // "id, name, email, password_hash"
        $placeholders = ':' . join(', :', array_keys($data)); // ":id, :name, :email, :password_hash"

        $db->prepare("REPLACE INTO users ($columns) VALUES ($placeholders)")->execute();

        $user->markAsPersisted();
    }
}
```

> *The example always does a `REPLACE` query, but you could do an `UPDATE` query if `isNew()` returns `false` instead.*

After an entity is saved, the gateway should call the `markAsPersisted` method, which will trigger an event and mark the entity as no longer being new (for `isNew()`).

If you're using a auto-generated identifier, you should retrieve it from the db layer and directly set the `id` property prior to calling `marktAsPersisted()`.

### Events

[](#events)

Entities may support events through a [PSR-14 compatible](https://www.php-fig.org/psr/psr-14/) event dispatcher. This allows additional abstraction for different services and is important when

Before you can add event listener, you need to register an event dispatcher. The entity doesn't create one itself.

```
use Jasny\Entity\Event;
use Jasny\Entity\EventListener\JsonCast;
use Jasny\EventDispatcher\EventDispatcher;

$listener = (new ListenerProvider)
    ->withListener(function(Event\Serialize $event): void {
        $assoc = $event->getPayload();

        if (isset($assoc['password'])) {
            $assoc['password_hashed'] = password_hash($assoc['password'], PASSWORD_DEFAULT);
            unset($assoc['password_hashed']);
        }

        $event->setPayload($assoc);
    })
    ->withListener(new JsonCast());

$dispatcher = new EventDispatcher($listener);

$user = new User;
$user->setEventDispatcher($dispatcher);
```

Typically the event dispatcher is added to an entity by the gateway. This means that the gateway should also be used when creating a new entity.

To add an event listener to an existing entity use the `addEventListener()` method of the entity.

```
$user->addEventListener(function(Event\ToJson $event): void {
    $assoc = $event->getPayload();
    unset($assoc['password_hashed']);

    $event->setPayload($assoc);
});
```

> *Note that since adding event listeners isn't defined by the PSR-14 standard, the `addEventListener()` method only works with [Jasny Event Dispatcher](https://github.com/jasny/event-dispatcher).*

The `dispatchEvent()` method takes an event and dispatches it to the listeners. It will return the passed event object, which may be modified by the event listeners.

```
$event = $user->dispatchEvent(new CustomEvent($user, $someData));
```

#### Event objects

[](#event-objects)

An event can be any object. The event lister are filtered on the object class.

Event classes of this library take the `$entity` and `$payload` as constructor arguments. The `getEntity()` method will return the emitting entity. You can get the payload using `getPayload()` and update it with `setPayload()`. The modified event is passed to subsequent listeners and used by the method triggering the event.

#### Entity events

[](#entity-events)

The library has the following events

- **BeforeSet** - Called by `set()`. Modifying the payload will effect the values that are set. This method can be used for casting the values to the correct type or filtering out properties that are not allowed to be changed manually.
- **AfterSet** - Called by `set()`, after updating the entity object. Modifying the payload has no effect.
- **Persisted** - Called by `markAsPersisted()`, which in turn should be called whenever the entity is saved to persistent storage like a DB.
- **ToAssoc** - Called by `toAssoc()`. Modifying the payload will affect the return value of this method.
- **ToJson** - Called by `jsonSerialize()`. Modifying the payload will affect the return value of this method.

#### Event listeners

[](#event-listeners)

- **ToAssocRecursive** - Recursively loop through all properties, also turning sub-entities into associative arrays.
- **JsonCast** - Recursively loop through all properties, casting `DateTime` objects to date/time strings and getting the json data for `JsonSerializable` objects.

###  Health Score

24

—

LowBetter than 32% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity12

Limited adoption so far

Community12

Small or concentrated contributor base

Maturity45

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 89.4% 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 ~4 days

Total

2

Last Release

2572d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/3379a93d51305df325df9045e1a8b205d195e4e8c01312dff53a000ee79002eb?d=identicon)[jasny](/maintainers/jasny)

---

Top Contributors

[![jasny](https://avatars.githubusercontent.com/u/100821?v=4)](https://github.com/jasny "jasny (363 commits)")[![Minstel](https://avatars.githubusercontent.com/u/6154708?v=4)](https://github.com/Minstel "Minstel (39 commits)")[![moesjarraf](https://avatars.githubusercontent.com/u/5793511?v=4)](https://github.com/moesjarraf "moesjarraf (2 commits)")[![Sarfaraaz](https://avatars.githubusercontent.com/u/2484595?v=4)](https://github.com/Sarfaraaz "Sarfaraaz (1 commits)")[![scrutinizer-auto-fixer](https://avatars.githubusercontent.com/u/6253494?v=4)](https://github.com/scrutinizer-auto-fixer "scrutinizer-auto-fixer (1 commits)")

### Embed Badge

![Health badge](/badges/jasny-entity/health.svg)

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

###  Alternatives

[symfony/event-dispatcher-contracts

Generic abstractions related to dispatching event

3.4k756.5M424](/packages/symfony-event-dispatcher-contracts)[league/event

Event package

1.6k141.6M184](/packages/league-event)[phpro/soap-client

A general purpose SoapClient library

8885.6M46](/packages/phpro-soap-client)[yohang/finite

A simple PHP Finite State Machine

1.3k3.5M10](/packages/yohang-finite)[mcp/sdk

Model Context Protocol SDK for Client and Server applications in PHP

1.4k423.9k30](/packages/mcp-sdk)[cognesy/instructor-php

The complete AI toolkit for PHP: unified LLM API, structured outputs, agents, and coding agent control

310107.9k1](/packages/cognesy-instructor-php)

PHPackages © 2026

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