PHPackages                             tobento/service-repository - 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. tobento/service-repository

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

tobento/service-repository
==========================

Repository interfaces for PHP applications.

2.0.3(1mo ago)017912MITPHPPHP &gt;=8.4

Since Mar 28Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/tobento-ch/service-repository)[ Packagist](https://packagist.org/packages/tobento/service-repository)[ Docs](https://www.tobento.ch)[ RSS](/packages/tobento-service-repository/feed)WikiDiscussions 2.x Synced 1mo ago

READMEChangelog (7)Dependencies (10)Versions (9)Used By (12)

Repository Service
==================

[](#repository-service)

Repository interfaces for PHP applications.

Table of Contents
-----------------

[](#table-of-contents)

- [Getting started](#getting-started)
    - [Requirements](#requirements)
    - [Highlights](#highlights)
- [Documentation](#documentation)
    - [Interfaces](#interfaces)
        - [Repository Interface](#repository-interface)
        - [Read Repository Interface](#read-repository-interface)
        - [Write Repository Interface](#write-repository-interface)
        - [Locales Aware Interface](#locales-aware-interface)
        - [Entity Factory Interface](#entity-factory-interface)
    - [Null Repository](#null-repository)
    - [Read Only Repository Adapter](#read-only-repository-adapter)
    - [Events Repository Adapter](#events-repository-adapter)
        - [Eventer](#eventer)
- [Credits](#credits)

---

Getting started
===============

[](#getting-started)

Add the latest version of the repository service project running this command.

```
composer require tobento/service-repository

```

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

[](#requirements)

- PHP 8.4 or greater

Highlights
----------

[](#highlights)

- Framework-agnostic, will work with any project
- Decoupled design

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

[](#documentation)

Interfaces
----------

[](#interfaces)

### Repository Interface

[](#repository-interface)

```
namespace Tobento\Service\Repository;

interface RepositoryInterface extends ReadRepositoryInterface, WriteRepositoryInterface
{
    //
}
```

### Read Repository Interface

[](#read-repository-interface)

```
namespace Tobento\Service\Repository;

interface ReadRepositoryInterface
{
    /**
     * Returns the found entity using the specified id (primary key)
     * or null if none found.
     *
     * @param int|string $id
     * @return null|object
     * @throws RepositoryReadException
     */
    public function findById(int|string $id): null|object;

    /**
     * Returns the found entity using the specified id (primary key)
     * or null if none found.
     *
     * @param int|string ...$ids
     * @return iterable
     * @throws RepositoryReadException
     */
    public function findByIds(int|string ...$ids): iterable;

    /**
     * Returns the found entity using the specified where parameters
     * or null if none found.
     *
     * @param array $where
     * @return null|object
     * @throws RepositoryReadException
     */
    public function findOne(array $where = []): null|object;

    /**
     * Returns the found entities using the specified parameters.
     *
     * @param array $where Usually where parameters.
     * @param array $orderBy The order by parameters.
     * @param null|int|array $limit The limit e.g. 5 or [5(number), 10(offset)].
     * @return iterable
     * @throws RepositoryReadException
     */
    public function findAll(array $where = [], array $orderBy = [], null|int|array $limit = null): iterable;

    /**
     * Returns the found column values using the specified parameters.
     *
     * @param string $column The column name for the values.
     * @param null|string $key The column name for the index key.
     * @param array $where Usually where parameters.
     * @param array $orderBy The order by parameters.
     * @param null|int|array $limit The limit e.g. 5 or [5(number), 10(offset)].
     * @return array
     * @throws RepositoryReadException
     */
    public function findColumn(
        string $column,
        null|string $key = null,
        array $where = [],
        array $orderBy = [],
        null|int|array $limit = null
    ): array;

    /**
     * Returns the number of items using the specified where parameters.
     *
     * @param array $where
     * @return int
     * @throws RepositoryReadException
     */
    public function count(array $where = []): int;
}
```

### Write Repository Interface

[](#write-repository-interface)

```
namespace Tobento\Service\Repository;

interface WriteRepositoryInterface
{
    /**
     * Create an entity.
     *
     * @param array $attributes
     * @return object The created entity.
     * @throws RepositoryCreateException
     */
    public function create(array $attributes): object;

    /**
     * Update an entity by id.
     *
     * @param string|int $id
     * @param array $attributes The attributes to update the entity.
     * @return object The updated entity.
     * @throws RepositoryUpdateException
     */
    public function updateById(string|int $id, array $attributes): object;

    /**
     * Update entities.
     *
     * @param array $where The where parameters.
     * @param array $attributes The attributes to update the entities.
     * @return iterable The updated entities.
     * @throws RepositoryUpdateException
     */
    public function update(array $where, array $attributes): iterable;

    /**
     * Delete an entity by id.
     *
     * @param string|int $id
     * @return object The deleted entity.
     * @throws RepositoryDeleteException
     */
    public function deleteById(string|int $id): object;

    /**
     * Delete entities.
     *
     * @param array $where The where parameters.
     * @return iterable The deleted entities.
     * @throws RepositoryDeleteException
     */
    public function delete(array $where): iterable;
}
```

### Locales Aware Interface

[](#locales-aware-interface)

You may implement the locales aware interface into your repository using the `HasLocales` trait.

```
use Tobento\Service\Repository\HasLocales;
use Tobento\Service\Repository\LocalesAware;
use Tobento\Service\Repository\RepositoryInterface;

class SomeRepository implements RepositoryInterface, LocalesAware
{
    use HasLocales;

    // ...
}
```

```
namespace Tobento\Service\Repository;

interface LocalesAware
{
    /**
     * Sets the locale.
     *
     * @param string $locale
     * @return static $this
     */
    public function locale(string $locale): static;

    /**
     * Sets the locale returing a new instance.
     *
     * @param string $locale
     * @return static
     */
    public function withLocale(string $locale): static;

    /**
     * Returns the locale.
     *
     * @return string
     */
    public function getLocale(): string;

    /**
     * Sets the locales.
     *
     * @param string ...$locales
     * @return static $this
     */
    public function locales(string ...$locales): static;

    /**
     * Sets the locales returning a new instance.
     *
     * @param string ...$locales
     * @return static
     */
    public function withLocales(string ...$locales): static;

    /**
     * Returns the locales.
     *
     * @return array
     */
    public function getLocales(): array;

    /**
     * Sets the locale fallbacks.
     *
     * @param array $localeFallbacks
     * @return static $this
     */
    public function localeFallbacks(array $localeFallbacks): static;

    /**
     * Sets the locale fallbacks returning a new instance.
     *
     * @param array $localeFallbacks
     * @return static
     */
    public function withLocaleFallbacks(array $localeFallbacks): static;

    /**
     * Returns the locale fallbacks.
     *
     * @return array
     */
    public function getLocaleFallbacks(): array;
}
```

### Entity Factory Interface

[](#entity-factory-interface)

```
namespace Tobento\Service\Repository;

interface EntityFactoryInterface
{
    /**
     * Create an entity from array.
     *
     * @param array $attributes
     * @return object The created entity.
     */
    public function createEntityFromArray(array $attributes): object;
}
```

Null Repository
---------------

[](#null-repository)

The `NullRepository` is a no-operation implementation of `RepositoryInterface`.
It accepts all read and write operations without performing any side effects and returns neutral, predictable values.

This makes it useful for:

- disabling persistence in development or testing environments
- providing a safe fallback when no repository is configured
- stubbing repository dependencies in prototypes
- avoiding conditional logic (`if ($repo) { ... }`)
- ensuring repository calls never throw or mutate state

### Features

[](#features)

- Implements the full `RepositoryInterface`
- All read operations return neutral values:
    - `null` for single-entity lookups
    - empty arrays/iterables for multi-entity queries
    - `0` for counts
- All write operations return simple objects based on the provided attributes
- No exceptions are thrown
- No state is stored and no side effects occur

### Returned Values Overview

[](#returned-values-overview)

MethodReturn Value`findById()``null``findByIds()``[]``findOne()``null``findAll()``[]``findColumn()``[]``count()``0``create()``(object)$attributes``updateById()``(object)$attributes``update()``[]``deleteById()``(object)['id' => $id]``delete()``[]`### Example

[](#example)

```
use Tobento\Service\Repository\NullRepository;

$repo = new NullRepository();

// Always returns null
$user = $repo->findById(1);

// Always returns empty iterable
$users = $repo->findAll(['active' => true]);

// Creates a simple object from attributes
$entity = $repo->create(['name' => 'Alice']);
// $entity->name === 'Alice'

// Update returns an object with the provided attributes
$updated = $repo->updateById(5, ['name' => 'Bob']);

// Delete returns an object containing the id
$deleted = $repo->deleteById(10);
// $deleted->id === 10
```

Read Only Repository Adapter
----------------------------

[](#read-only-repository-adapter)

Any repository implementing the `RepositoryInterface::class` can be made read-only by decorating them using the `ReadOnlyRepositoryAdapter::class`:

```
use Tobento\Service\Repository\ReadOnlyRepositoryAdapter;
use Tobento\Service\Repository\RepositoryInterface;

$readOnlyRepository = new ReadOnlyRepositoryAdapter(
    repository: $repository, // RepositoryInterface
);
```

Events Repository Adapter
-------------------------

[](#events-repository-adapter)

Any repository implementing the `ReadRepositoryInterface::class` or `WriteRepositoryInterface::class` can be made to dispatch default events by decorating them using the `EventsRepositoryAdapter::class`:

```
use Psr\EventDispatcher\EventDispatcherInterface;
use Tobento\Service\Repository\EventsRepositoryAdapter;
use Tobento\Service\Repository\ReadRepositoryInterface;
use Tobento\Service\Repository\WriteRepositoryInterface;
use Tobento\Service\Repository\Event;

$eventsRepository = new EventsRepositoryAdapter(
    eventDispatcher: $eventDispatcher, // EventDispatcherInterface
    repository: $repository, // ReadRepositoryInterface or WriteRepositoryInterface

    // if false (default) event attributes get used on write methods
    immutableAttributes: false,
);
```

**Default Events**

EventDescription`Event\Retrieved::class`The event will dispatch **after** an entity is retrieved from the read methods only.`Event\Creating::class`The event will dispatch **before** an entity is created.`Event\Created::class`The event will dispatch **after** an entity is created.`Event\Updating::class`The event will dispatch **before** an entity is updated.`Event\Updated::class`The event will dispatch **after** an entity is updated.`Event\Deleting::class`The event will dispatch **before** an entity is deleted.`Event\Deleted::class`The event will dispatch **after** an entity is deleted.### Eventer

[](#eventer)

The eventer may be used to easily create a `EventsRepositoryAdapter::class` if you want only to have certain events dispatched.

**Create Eventer**

```
use Psr\EventDispatcher\EventDispatcherInterface;
use Tobento\Service\Repository\EventerInterface;
use Tobento\Service\Repository\Eventer;

$eventer = new Eventer(
    eventDispatcher: $eventDispatcher, // EventDispatcherInterface
);

var_dump($eventer instanceof EventerInterface);
// bool(true)
```

**Using Eventer**

```
use Tobento\Service\Repository\EventerInterface;

class SomeService
{
    public function createAction(EventerInterface $eventer)
    {
        $entity = $eventer
            ->repository($this->someRepository)
            ->create(['title' => 'Lorem']);

        // or
        $entity = $eventer
            ->repository(
                repository: $this->someRepository,
                immutableAttributes: true, // default is false
            )
            ->create(['title' => 'Lorem']);
    }
}
```

Credits
=======

[](#credits)

- [Tobias Strub](https://www.tobento.ch)
- [All Contributors](../../contributors)

###  Health Score

50

—

FairBetter than 95% of packages

Maintenance91

Actively maintained with recent releases

Popularity14

Limited adoption so far

Community17

Small or concentrated contributor base

Maturity67

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

Recently: every ~45 days

Total

9

Last Release

45d ago

Major Versions

1.x-dev → 2.02025-09-30

PHP version history (2 changes)1.0.0PHP &gt;=8.0

2.0PHP &gt;=8.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/055d6a1b5c2384bb179c75ab0b55914231d898fdc4dffeb30770f81200e52206?d=identicon)[TOBENTOch](/maintainers/TOBENTOch)

---

Top Contributors

[![tobento-ch](https://avatars.githubusercontent.com/u/16684832?v=4)](https://github.com/tobento-ch "tobento-ch (19 commits)")

---

Tags

phppackagerepositorytobento

###  Code Quality

TestsPHPUnit

Static AnalysisPsalm

Type Coverage Yes

### Embed Badge

![Health badge](/badges/tobento-service-repository/health.svg)

```
[![Health](https://phpackages.com/badges/tobento-service-repository/health.svg)](https://phpackages.com/packages/tobento-service-repository)
```

PHPackages © 2026

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