Download the PHP package rasuvaeff/yii3-idempotency without Composer

On this page you can find all versions of the php package rasuvaeff/yii3-idempotency. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package yii3-idempotency

rasuvaeff/yii3-idempotency

Stable Version Total Downloads Build Static analysis Coverage PHP License Русская версия

Idempotency key middleware for Yii3 APIs. Prevents duplicate processing of POST/PUT/PATCH requests.

Using an AI coding assistant? llms.txt contains a compact API reference you can feed to the LLM. Projects using the llm/skills Composer plugin also get this package's agent skill synced into .agents/skills/ automatically on install.

Requirements

Installation

Usage

Basic setup

How it works

Scenario Result
No idempotency key, PassThrough policy Request passes through
No idempotency key, Reject policy 400 Bad Request
First request with key Handler processes, response stored
Same key + same payload Stored response replayed (handler not called)
Same key + different payload 422 Unprocessable Content
Same key + same payload while first request is still processing 409 Conflict
Same key + different payload while first request is still processing 422 Unprocessable Content when the storage implements ClaimedFingerprintProvider, otherwise 409 Conflict
Malformed key (too long, illegal characters) 400 Bad Request
Same key + same payload, different caller Handler processes again — the two callers never share a record
Non-2xx handler response (3xx/4xx/5xx) Response NOT stored — claim released, client may retry with the same key
Handler throws, no DomainFailureRenderer Claim released, throwable rethrown — retry re-runs the handler
Handler throws a domain failure, renderer configured Rendered response stored and replayed like a success (see below)
Non-configured method (e.g. GET, DELETE) Passes through untouched — idempotency applies only to methods (default POST/PUT/PATCH)
Expired record Request processed as new

Failure classification

By default every throwable released the claim, so a deterministic business outcome (PaymentDeclined, InsufficientFunds) was re-executed on retry. Give the middleware a DomainFailureRenderer and domain failures become part of the cached outcome instead:

DefaultFailureClassifier decides, in order:

Throwable Kind Effect
Matches an explicit override (instanceof, declaration order) as configured as below
Implements RetryableFailure Infrastructure Claim released, retry re-runs the handler
Any other \Exception Domain Rendered, stored, replayed for the whole TTL
\Error and everything else Infrastructure Claim released, retry re-runs the handler

FailureKind::Bug is never inferred — declare it via an override. Both Bug and Infrastructure release the claim and rethrow; the distinction is for your own reporting.

The middleware caches exactly what the renderer returns, so the first attempt and every replay are byte-identical. A renderer that returns null declines the failure: the claim is released and the original throwable is rethrown. Without a renderer nothing changes — every throwable stays retryable.

Only the throwing path is classified. A handler that returns a 4xx response still releases the claim.

Caller scoping

scopeResolver has no default, on purpose. A keyspace shared by every caller lets one client replay another client's cached response — and the replay path returns the stored response without ever entering the handler, so it never reaches the handler's authorization checks either. The same gap lets a client occupy someone else's key and lock them out for the whole TTL.

A request with no principal resolves to the anonymous namespace, which every anonymous caller shares — there is no identity to separate them by. Do not put caller-private data behind an idempotent endpoint reachable anonymously. The namespace is tagged by caller state (caller:identity:<id> against caller:anonymous:<name>), so an authenticated caller whose identifier happens to read anonymous never lands in it.

Opt-out. SharedKeyspaceScopeResolver puts every caller in one keyspace, which is the pre-2.0 behaviour. It is safe only when a single principal can reach the middleware — a single-tenant deployment, an internal service with one trusted client, or an endpoint whose responses hold nothing caller-private.

Endpoint scoping

A key also identifies the request but not the endpoint, so the same key sent to two endpoints would collide on one record. CompositeScopeResolver stacks the endpoint namespace on top of the caller:

The storage key becomes sha256(scope . "\0" . key) — a fixed 64 characters, so a long-but-valid client key can never be pushed past the 255-character limit. Stored keys are therefore opaque: scoping trades greppable keys for collision freedom. A scope name that would itself exceed 1024 characters (a long path, a long principal identifier, several dimensions joined) is collapsed to its hash rather than rejected, so request data cannot turn a request into a 500 by its length alone. Other resolution failures — an attribute holding a value the resolver cannot stringify, for example — still surface as errors: they are deployment mistakes, not client input.

Each dimension is length-prefixed before the parts are joined (21:caller:identity:alice | 16:POST /api/orders), so the separator appearing inside a name cannot make two different compositions resolve to one scope.

ScopedIdempotencyKeyExtractor still applies a scope at the extractor level and is kept for compatibility, but scoping the middleware is the supported way: it is the one place that cannot be left out.

Keys from the payload

For queue handlers and command-bus consumers the key lives inside the payload rather than in a header:

The path is read from the parsed body with dot notation. Segments are matched literally, so a payload key containing a dot is not addressable. A value that resolves to nothing (missing, null, or not a string/int) throws MissingKeyException; pass required: false to resolve to null instead and let the middleware policy decide.

Configuration

DomainFailureRenderer has no default binding — it is an application concern, and wiring one in your own config/common/di/*.php is what turns domain-failure caching on. FailureClassifier needs wiring only to override DefaultFailureClassifier, which the middleware falls back to on its own.

Public API

Class Description
IdempotencyMiddleware PSR-15 middleware
IdempotencyKey Validated key value object (1-255 chars, [A-Za-z0-9._-]+)
IdempotencyFingerprint Request fingerprint (method + path + query + body hash)
IdempotencyRecord Stored record with TTL
IdempotencyResponse Captured response (status, headers, body)
IdempotencyStorage Interface: load, claim, store, release
ClaimedFingerprintProvider Optional storage capability: the fingerprint of an in-flight claim — lets the middleware answer 422 instead of a retryable 409 when a key is reused with a different payload mid-flight
IdempotencyKeyExtractor Interface for key extraction strategies
InMemoryIdempotencyStorage In-memory implementation (for testing)
HeaderIdempotencyKeyExtractor Extracts key from request header
PayloadIdempotencyKeyExtractor Extracts key from the parsed body by dot path
ScopedIdempotencyKeyExtractor Decorator namespacing the extracted key with a scope
IdempotencyScope Validated scope name; also resolves to itself. of() collapses an over-long name to its hash
IdempotencyScopeResolver Interface for per-request scope resolution
RequestAttributeScopeResolver Namespaces the key by the authenticated principal in a request attribute
SharedKeyspaceScopeResolver Puts every caller in one keyspace — the documented opt-out
CompositeScopeResolver Joins several scope dimensions into one
RequestTargetScopeResolver Derives the scope from METHOD /path
IdempotencyPolicy Enum: PassThrough, Reject
FailureKind Enum: Domain, Infrastructure, Bug
FailureClassifier Interface: classifies a throwable into a FailureKind
DefaultFailureClassifier Marker/type-based classifier with explicit overrides
RetryableFailure Marker interface for exceptions a retry may resolve
DomainFailureRenderer Interface: renders a domain failure into a cacheable response
MissingKeyException Thrown when a required key is absent from the request

Security

Examples

See examples/ for runnable scripts.

Development

make test-coverage and make mutation bootstrap pcov inside the composer:2 container because the base image has no coverage driver.

License

BSD-3-Clause. See LICENSE.md.


All versions of yii3-idempotency with dependencies

PHP Build Version
Package Version
Requires php Version 8.3 - 8.5
psr/clock Version ^1.0
psr/http-factory Version ^1.0
psr/http-message Version ^2.0
psr/http-server-handler Version ^1.0
psr/http-server-middleware Version ^1.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package rasuvaeff/yii3-idempotency contains the following files

Loading the files please wait ...