PHPackages                             lmc/cqrs-types - 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. lmc/cqrs-types

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

lmc/cqrs-types
==============

A library containing types (interfaces and value objects) to help with Queries and Commands

3.2.0(2y ago)138.0k↓36.2%14MITPHPPHP ^8.2

Since May 12Pushed 2y ago14 watchersCompare

[ Source](https://github.com/lmc-eu/cqrs-types)[ Packagist](https://packagist.org/packages/lmc/cqrs-types)[ RSS](/packages/lmc-cqrs-types/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (8)Dependencies (10)Versions (11)Used By (4)

LMC CQRS Types
==============

[](#lmc-cqrs-types)

[![cqrs-types](https://camo.githubusercontent.com/d2e4a1ae4631bc4819c80a7abc5aa314a298c371e9ab906ccf0eecdd16e00aaa/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f637172732d74797065732d707572706c652e737667)](https://github.com/lmc-eu/cqrs-types)[![Latest Stable Version](https://camo.githubusercontent.com/86b50d935ba2fb7d2570944241f7f40f27e5fbf0a9fe04118c919a90fc1035e3/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6c6d632f637172732d74797065732e737667)](https://packagist.org/packages/lmc/cqrs-types)[![Tests and linting](https://github.com/lmc-eu/cqrs-types/actions/workflows/tests.yaml/badge.svg)](https://github.com/lmc-eu/cqrs-types/actions/workflows/tests.yaml)[![Coverage Status](https://camo.githubusercontent.com/24981f3a9e5331cbe970324f94070d8ef4ef5b64f267a69f57d02238ff903e19/68747470733a2f2f636f766572616c6c732e696f2f7265706f732f6769746875622f6c6d632d65752f637172732d74797065732f62616467652e7376673f6272616e63683d6d61696e)](https://coveralls.io/github/lmc-eu/cqrs-types?branch=main)

> This library contains types, value objects, interfaces and base implementation for CQRS library. So anyone can easily write an extension for it.

Table of contents
-----------------

[](#table-of-contents)

- [Installation](#installation)
- [Interfaces (types)](#interfaces-types)
    - Queries
        - [Query Interface](#query-interface)
        - [Query Fetcher](#query-fetcher-interface)
        - [Query Handler](#query-handler-interface)
    - Commands
        - [Command](#command-interface)
        - [Command Sender](#command-sender-interface)
        - [Send Command Handler](#send-command-handler-interface)
    - Common
        - [Response Decoder](#response-decoder-interface)
        - [Profiler Formatter](#profiler-formatter-interface)
    - [Features](#features)
        - [Caching](#cache-interface)
        - [Profiling](#profileable-interface)
- [Base Implementations](#base-implementations)
    - [Handlers](#handlers)
    - [Decoders](#decoders)
- [Other CQRS Libraries](#other-cqrs-libraries)

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

[](#installation)

```
composer require lmc/cqrs-types
```

Interfaces (types)
------------------

[](#interfaces-types)

> There are many interfaces and types here, which are implemented in [other CQRS libraries](#other-cqrs-libraries)

### Query Interface

[](#query-interface)

The main interface for all Queries. Query is a request which fetch a data without changing anything. It is responsible for declaring and creating a request, which will be handled by `QueryHandlerInterface`. An object implementing Query Interface may implement [feature](#features) and it should be handled by a `QueryFetcher`.

Available features:

- caching
- profiling

### Query Fetcher Interface

[](#query-fetcher-interface)

An interface for a Query Fetcher (see [Handler/QueryFetcher](https://github.com/lmc-eu/cqrs-handler#query-fetcher)).

It is responsible for

- finding a Query Handler based on Query request type
- handle all Query features
    - caching
        - requires an instance of `Psr\Cache\CacheItemPoolInterface`
    - profiling
        - requires an instance of `Lmc\Cqrs\Handler\ProfilerBag`
- decoding a response from the Query Handler

MethodDescription`fetch`It fetches a response from a Query by a handler supporting the Query and decodes it. It uses a continuation pattern - `OnSuccess` and `OnError` callbacks are passed to the method directly and one of them is called with a result or an error. It never throws an exception unless an `OnSuccess` or `OnError` throws it.`fetchFresh`It works just like a `fetch` but it doesn't use a `GetCachedHandler` so it always fetch a fresh response out of a Query.`fetchAndReturn`It works just like a `fetch` but it hides a continuation pattern and instead returns a response directly. It may throw an exception, when an error occurs while handling a query.`fetchFreshAndReturn`It works just like a `fetchAndReturn` but it doesn't use a `GetCachedHandler` so it always fetch a fresh response out of a Query.`addHandler`Register a QueryHandler with priority.`getHandlers`Returns a list of all handlers, sorted by priority.`addDecoder`Register a ResponseDecoder with priority.`getDecoders`Returns a list of all response decoders, sorted by priority.`enableCache`Enables cache (requires an instance of `CacheItemPoolInterface` to really use cache)`disableCache`Disables cache (both storing and retrieving).`isCacheEnabled`Returns whether a cache is enabled.`invalidateQueryCache`Invalidates a cache item by given Query (if that query implements a `CacheableInterface` and `CacheItemPoolInterface` is set and item is in cache)`invalidateCacheItem`Invalidates a cache item by given cache key hash (if `CacheItemPoolInterface` is set and item is in cache)### Query Handler Interface

[](#query-handler-interface)

It is responsible for handling a specific Query request and passing a result into `OnSuccess` callback. It must say which request it supports and it must not be able to handle a different request. When unsupported request is passed to handle method, it must pass `UnsupportedRequestException` into `OnError` callback. It must not throw any exception, all exception must be passed into `OnError` callback.

If necessary it may prepare a Query (for example inject a Client) - yet `prepare` method should not change a Query type or its content. It should prepare only supported queries. It should not throw any exception either.

---

### Command Interface

[](#command-interface)

The main interface for all Commands. Command is a request which change a data and may return result data. It is responsible for declaring and creating a request, which will be handled by `SendCommandHandlerInterface`. An object implementing Command Interface may implement [feature](#features) and it should be handled by a `CommandSender`.

Available features:

- profiling

### Command Sender Interface

[](#command-sender-interface)

An interface for a Command Sender (see [Handler/CommandSender](https://github.com/lmc-eu/cqrs-handler#command-sender)).

It is responsible for

- finding a Send Command Handler based on Command request type
- handle all Command features
    - profiling
        - requires an instance of `Lmc\Cqrs\Handler\ProfilerBag`
- decoding a response from the Send Command Handler

MethodDescription`send`It sends a command by a handler supporting the Command and decodes a response. It uses a continuation pattern - `OnSuccess` and `OnError` callbacks are passed to the method directly and one of them is called with a result or an error. It never throws an exception unless an `OnSuccess` or `OnError` throws it.`sendAndReturn`It works just like a `send` bat it hides a continuation pattern and instead returns a response directly. It may throw an exception, when an error occurs while handling a query.`addHandler`Register a QueryHandler with priority.`getHandlers`Returns a list of all handlers, sorted by priority.`addDecoder`Register a ResponseDecoder with priority.`getDecoders`Returns a list of all response decoders, sorted by priority.### Send Command Handler Interface

[](#send-command-handler-interface)

It is responsible for handling a specific Command request and passing a result into `OnSuccess` callback. It must say which request it supports and it must not be able to handle a different request. When unsupported request is passed to handle method, it must pass `UnsupportedRequestException` into `OnError` callback. It must not throw any exception, all exception must be passed into `OnError` callback.

If necessary it may prepare a Command (for example inject a Client) - yet `prepare` method should not change a Command type or its content. It should prepare only supported commands. It should not throw any exception either.

---

### Response Decoder Interface

[](#response-decoder-interface)

It is meant to decode a response (a result of either `QueryHandlerInterface` or a `SendCommandHandlerInterface`). Decoder itself should be as small as possible and it should only support the one type to decode. Decoders should (*and are in a default implementation*) be used by a priority one by one.

If you need a decoder to be *final* and no other decoding to be done, you must return a `DecodedValue` object.

- QueryFetcher and CommandSender is responsible not to send a `DecodedValue` to any other decoder

#### It should be pure.

[](#it-should-be-pure)

The response should be decoded in the same way everytime, in that case it can be safely cached.

If you need to do some impure operations in your decoder, you should use `ImpureResponseDecoderInterface` instead. It works exactly the same as a pure decoder but in the addition the `QueryFetcher` knows, that a decoding process is not pure, so it may do some extra stuff. For example `QueryFetcher` should cache the result **before** the first impure decoding, so it won't cache the wrong result.

If an unsupported response is passed to decode method, it should return it untouched. It must not throw an exception.

There is also one predefined Response Decoder to decode a json string into an array - `JsonResponseDecoder`.

### Profiler Formatter Interface

[](#profiler-formatter-interface)

When a Command or a Query implements `Feature\ProfileableInterface` QueryFetcher/CommandSender will create a `ProfilerItem` with some information. The `ProfilerItem` contains a raw data about a duration, request type, response, error and more and it is meant to be shown in Symfony Profiler (if you use a [CQRS bundle](https://github.com/lmc-eu/cqrs-bundle)). Profiler Formatter format those items to provide a better experience than just a raw data, which might be lazy or unreadable without formatting. It is responsible to format a `ProfilerItem` to the `ProfilerItem` again, so it can get/set all of `ProfilerItem` properties.

There is a `FormattedValue` Value object to help with a formatting, it can be passed to the most of the `ProfilerItem` properties as a value. It contains both original and formatted value.

Profiler formatter can even further format already `FormattedValue`. Multiple Formatters should be called by priority on the `ProfilerItem` one by one to create the most readable form of a `ProfilerItem`.

There is also one predefined Profiler Formatter to format (*decode*) a json string into an array - `JsonProfilerFormatter`.

---

Features
--------

[](#features)

### Cacheable Interface

[](#cacheable-interface)

It allows to store and load an object implementing this interface to `Psr\Cache\CacheItemPoolInterface`. It uses a `CacheKey` which should be as unique as possible.

**NOTE**: It is also required to set up `Psr\Cache\CacheItemPoolInterface` implementation to `QueryFetcher`.

### Profileable Interface

[](#profileable-interface)

It allows a profiling the object implementing this interface. `ProfilerId` is a string, which does not have to be unique.

Base Implementations
--------------------

[](#base-implementations)

> Base implementations offers a method(s) which will be mostly needed in implementing Handlers etc.

### Handlers

[](#handlers)

> `AbstractQueryHandler` and `AbstractSendCommandHandler`

Offers a base implementation for asserting a supported Command/Query given to the handle method and base `prepare` method, which does nothing to the query/command (as most of handlers won't need it).

It supposed to be used like follows

```
class MyQueryHandler extends AbstractQueryHandler
{
    public function supports(QueryInterface $query): bool
    {
        return $query->getRequestType() === ExpectedRequestClass::class;
    }

    public function handle(QueryInterface $query, OnSuccessInterface $onSuccess, OnErrorInterface $onError): void
    {
        if (!$this->assertIsSupported(ExpectedRequestClass::class, $query, $onError)) {
            return;
        }

        try {
            $response = ...;    // handle query/command ...
            $onSuccess($response);
        } catch (\Throwable $e) {
            $onError($e);
        }
    }
}
```

### Decoders

[](#decoders)

#### CallbackResponseDecoder

[](#callbackresponsedecoder)

If you need a quick way of decoding a response, you can use this Callback Response Decoder, which allows you to pass a function to do decoding.

```
$decoder = new CallbackResponseDecoder(
    fn (string $response, $initiator) => is_string($response),
    fn (string $response) => sprintf('decoded:%s', $response),
);
```

#### JsonResponseDecoder

[](#jsonresponsedecoder)

It decodes a string which contains a json into decoded array.

---

Other CQRS Libraries
--------------------

[](#other-cqrs-libraries)

- [Handler](https://github.com/lmc-eu/cqrs-handler)
- [Bundle](https://github.com/lmc-eu/cqrs-bundle)
- [HTTP extension](https://github.com/lmc-eu/cqrs-http)
- [SOLR extension](https://github.com/lmc-eu/cqrs-solr)

###  Health Score

38

—

LowBetter than 85% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity32

Limited adoption so far

Community17

Small or concentrated contributor base

Maturity71

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

Recently: every ~176 days

Total

9

Last Release

803d ago

Major Versions

1.1.0 → 2.0.02021-08-09

2.3.0 → 3.0.02022-04-22

PHP version history (3 changes)1.0.0PHP ^7.4

3.0.0PHP ^8.1

3.2.0PHP ^8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/2bdf0b9957c08a48e70a52fce74fc4f1add30b12d442450d5e2b48854fc98b21?d=identicon)[MortalFlesh](/maintainers/MortalFlesh)

---

Top Contributors

[![MortalFlesh](https://avatars.githubusercontent.com/u/6317184?v=4)](https://github.com/MortalFlesh "MortalFlesh (34 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/lmc-cqrs-types/health.svg)

```
[![Health](https://phpackages.com/badges/lmc-cqrs-types/health.svg)](https://phpackages.com/packages/lmc-cqrs-types)
```

###  Alternatives

[sylius/sylius

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

8.4k5.6M651](/packages/sylius-sylius)[kreait/firebase-php

Firebase Admin SDK

2.4k39.7M72](/packages/kreait-firebase-php)[tempest/framework

The PHP framework that gets out of your way.

2.1k23.1k9](/packages/tempest-framework)[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)[anthropic-ai/sdk

Anthropic PHP SDK

129134.7k5](/packages/anthropic-ai-sdk)[neos/flow

Flow Application Framework

862.0M451](/packages/neos-flow)

PHPackages © 2026

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