PHPackages                             morebec/orkestra-privacy - 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. morebec/orkestra-privacy

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

morebec/orkestra-privacy
========================

Orkestra Component providing Privacy utilities.

v2.5.6(3y ago)24151Apache-2.0PHPPHP &gt;=7.4

Since Apr 26Pushed 3y ago1 watchersCompare

[ Source](https://github.com/Morebec/orkestra-privacy)[ Packagist](https://packagist.org/packages/morebec/orkestra-privacy)[ RSS](/packages/morebec-orkestra-privacy/feed)WikiDiscussions 2.x Synced 3w ago

READMEChangelogDependencies (5)Versions (23)Used By (1)

Privacy
=======

[](#privacy)

The Privacy component proposes as set of interfaces to a `PersonalInformationStore` which can be used to centralise all Personally Identifiable Information (PII) of a user as well as storing additional data such as the reasons, the processing operations or the legal basis for storing such information.

It does not offer any implementation (other than an In Memory one for tests).

> For an actual implementation you can check out the official PostgreSQLPersonalInformationStore which is a ready-made PostgreSQL implementation with support for encryption.

One of its primary goals is to provide a solution to Event Sourced Application to be able to remain immutable while allowing to have forgettable personal data.

Event Sourcing
--------------

[](#event-sourcing)

One of the challenges regarding privacy regulation and Event Sourcing is that these privacy regulations allows data subject to request to have their personal data removed from a system, where event sourced system are immutable in nature.

There are three common ways to solve this, with varying degrees of complexity and effectiveness:

### Mutable Event Store

[](#mutable-event-store)

One possible way is to have a mutable event store, i.e. have an implementation of an event store that can have some of its events deleted. Using a RDBMS or Mongo Db based event store technically allows one to do this quite easily. The downside of this is that the "audit for free" promise of event sourcing is no longer possible as data can be tempered with on a conceptual level, and from within the application.

Another downside of this strategy, is that it requires careful manipulation as changing the "past" might have hard to predict side effects and render the application unstable or unusable.

### Forgettable Event Payloads

[](#forgettable-event-payloads)

One solution that tries to keep the event store immutable, is to avoid saving the data in the event store directly but instead, saving references to that data in another store secured with encryption:

```
UserRegistered
{
    username: personal-data/x54tufojs536pzeqhelshvd7
    fullname: personal-data/folshvd7js536pzeqhex54tu
    password: personal-data/x134s5do6pzxqhelshvd8f
}
```

The challenges this strategy brings, is that the consumers of the events that requires access to the raw data, will need to query the Personal Information Store, which adds complexity and might have an impact on performance.

### Cryptographic Erasure

[](#cryptographic-erasure)

Cryptographic Erasure is a strategy where one encrypts the data before saving them in events and then stores the decryption key in another storage. When a user invokes the right to be forgotten, the decryption key is simply discarded, rendering the information obsolete and no longer accessible. It uses a similar mindset to the forgettable payloads the difference being that the actual data is kept in the event store in an encrypted form.

It has the same challenges as the *Forgettable Event Payloads* strategy as well as additional ones related to cryptography such as key rotation, or encryption weakening over time. Indeed, if a value was encrypted with an algorithm that is discovered to be weak or ineffective in the future the data could still be recoverable.

One additional thing to note is that it is still unclear whether this is a legal measure since the data is not technically deleted as required by the GDPR for example:

Even in an encrypted form, personal information is still considered by the GDPR as Personal Data:

> *"A confidentiality breach on personal data that were encrypted with a state-of-the-art algorithm is still a personal data breach, and has to be notified to the authority."*

### Summary

[](#summary)

The privacy component can be used to support both the Mutable Event Store and Cryptographic erasure as the Personal Information Store's API simply provides Find, Upsert and Delete operations. From a technical point of view it is advised to use the "Forgettable Payload" strategy as opposed to the other two mentioned as it is the one that provides the most future-proof and compliant solution.

For the performance hits it could present, multiple strategies can be performed to minimize this.

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

[](#installation)

```
composer require morebec/orkestra-orkestra-privacy
```

Usage
-----

[](#usage)

In order to fully use the component you will need an implementation of the `PersonalInformationStoreInterface`.

The official PostgreSQLPersonalInformationStore is a ready-made implementation with support for encryption.

The storage works with some core concepts:

- **Personal Data** represents a PII value such as a person's name, email address, phone number, birthdate etc as well as additional information regarding how the data was obtained, for what purposes and for how long it should be retained.
- **Personal Token** represents a token that is used internally by the application to identify a given person. Such as an internal UUID, in other words the owner of Personal Data. For GDPR compliance this value should not be natural key and easily disposable, i.e. it should not be used to identify the natural person after an erasure of their data. It serves as a namespace for a set of related values.
- **Reference Token** Represents a reference to some given Personal Data that can be used in the application to reference the data contained in the store.
- **Key** Corresponds to a key name associated with a piece personal data, e.g. email address, username, phone number etc.

### Adding Personal Data

[](#adding-personal-data)

To add personal data to the store, one must use the `PersonalData` class or an implementation of the `PersonalDataInterface` and add it to the store:

```
use Morebec\Orkestra\Privacy\PersonalData;

$personalToken='usr123456';

$data = new PersonalData($personalToken, 'emailAddress' /* key */, 'jane.doe@email.com' /* value */, 'registration_form' /* source */);
$data->disposedAt($clock->now()->addDays(15));

// You can use this reference token to reference this personal data within the store in your application code.
$referenceToken = $store->put($data);
```

The value can be any PHP scalar primitive or array of scalar primitives.

> If an entry of Personal Data for the same `personal token` and `key` combination exists, it will be overwritten, see the Updating Data section for more information.

### Retrieving Personal Data

[](#retrieving-personal-data)

The primary way of retrieving data is using the `reference token` of the data:

```
$data = $store->findOneByReferenceToken($referenceToken);
```

The returned value is an instance of `RecordedPersonalData` which is an immutable data structure around personal data.

If the data does not exist, `null` will be returned.

It is also possible to query the personal store for a specific `key` of a `personal token`:

```
// Data can also be retrieved in an number of ways:
$data = $store->findOneByKeyName('user123456', 'emailAddress');
```

One can also query by `personal token` to obtain all the related personal data present in the store:

```
// Returns an array of all personal data related to a personal token.
$data = $store->findByPersonalToken('user123456');
```

Again, if the data does not exist, `null` will be returned.

### Updating Data

[](#updating-data)

Updating data can be performed simply by overwriting some personal data already existing data with the `put` method:

```
use Morebec\Orkestra\Privacy\PersonalData;
$data = new PersonalData('usr123456', 'emailAddress', 'jane.doe123@email.com', 'account_settings');

$referenceToken = $store->put($data);
```

> If the data did not exist, it will be equivalent to adding new data to the store.

Or using the more explicit `replace` method:

```
use Morebec\Orkestra\Privacy\PersonalData;
$data = new PersonalData('usr123456', 'emailAddress', 'jane.doe123@email.com', 'account_settings');

$referenceToken = $store->replace($referenceToken, $data);
```

### Removing Data

[](#removing-data)

There are two different ways to remove data form the store.

The first one is by specifying the `personal token` and the `key` combination:

```
$store->removeByKeyName('user123456', 'emailAddress');
```

The other way is by specifying only the personal token with the `erase` method:

```
// Deletes all records for a given personal token.
$store->erase('user123456');
```

This will have for effect of removing all personal information related to that `personal token`

### Removing Disposable Data

[](#removing-disposable-data)

The `PersonalDataInterface` has a value indicating the DateTime at which the data should be considered disposable. This disposable nature is used in order not to store information indefinitely and without active use in the store. To easily clean up the store from this expired data, this package contains a `DisposedPersonalDataRemoverInterface`:

```
$remover->run(); // Will remove all disposable data as of the current date time.
```

###  Health Score

29

—

LowBetter than 57% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity15

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity62

Established project with proven stability

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

Recently: every ~58 days

Total

22

Last Release

1181d ago

PHP version history (2 changes)2.0PHP &gt;=7.3

v2.3.3PHP &gt;=7.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/10d7f5561446f2d4df4413803946e9f77175155d241f78bd65c0dd94e6caffc5?d=identicon)[jwillp](/maintainers/jwillp)

---

Top Contributors

[![jwillp](https://avatars.githubusercontent.com/u/5913483?v=4)](https://github.com/jwillp "jwillp (1 commits)")

---

Tags

gdprorkestraphpprivacy

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/morebec-orkestra-privacy/health.svg)

```
[![Health](https://phpackages.com/badges/morebec-orkestra-privacy/health.svg)](https://phpackages.com/packages/morebec-orkestra-privacy)
```

PHPackages © 2026

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