mpyw/unique-violation-detector
Detects and normalizes unique constraint violation errors across MySQL, PostgreSQL, and SQLite. Inspects PDO exceptions and SQLSTATE codes so your PHP/Laravel app can reliably catch duplicate-key errors and handle retries or upserts without brittle driver-specific checks.
Architecture fit. mpyw/unique-violation-detector is a leaf-level, framework-agnostic utility with no service provider, no configuration surface, and no runtime bootstrapping. It answers one narrow question — "was this PDOException caused by a primary key, unique key, or unique constraint violation?" — by inspecting SQLSTATE and driver-specific error codes. In a Laravel codebase it belongs in the persistence/infrastructure layer, wrapped around write paths (repository methods, upsert handlers, queued jobs) that need to translate a database conflict into domain behavior: an idempotent retry, a 409 Conflict response, a "user already exists" validation error, or a deduplicated job payload. Architecturally it is a good fit precisely because it is disposable and contained — it does not leak into controllers or models if adopted behind a small internal adapter.
Integration feasibility. High. A single composer require, no migrations, no published config. The realistic adoption cost is measured in hours, not sprints. The real work is not installing the package but deciding where conflict detection belongs in your domain and adding integration tests against your actual database engine and version.
Technical risk. Low blast radius, moderate correctness risk:
Illuminate\Database\UniqueConstraintViolationException, which covers the same ground for Eloquent/query-builder paths. For a modern Laravel app, this package is largely redundant unless you need it in legacy (Laravel 8/9) code, non-Eloquent PDO code, or Doctrine-driven paths.Key questions. Which Laravel and PHP versions are in scope? Which database engines and versions (MySQL 8 vs. MariaDB, PostgreSQL, SQLite, SQL Server)? Does Laravel's native exception already satisfy every path we care about? Who owns the code if the maintainer stops? Does the package's driver matrix match ours?
Stack fit. Works anywhere PDO is used: Eloquent, the query builder, Doctrine DBAL, raw PDO. The natural placement is a thin internal abstraction — e.g., a ConflictDetector interface with a package-backed implementation — so call sites depend on our contract, not on the vendor API. That keeps swap-out to a one-file change if we later standardize on Laravel's native exception.
Migration path. Sequence by framework version rather than by feature:
UniqueConstraintViolationException; skip this package.Compatibility. Verify against each engine and major version actually deployed. Error codes differ across MySQL, MariaDB, PostgreSQL, SQLite, and SQL Server, and major-version upgrades can shift message formats. Run the package's detection against a live database in CI, not against mocks.
Sequencing.
ConflictDetector abstraction and back it with the package.Maintenance. Negligible code footprint, MIT license, no transitive dependency risk. The maintenance burden is governance, not code: pin the version, vendor or fork if needed, and record the decision in an ADR so a future Laravel upgrade knows why the dependency exists and when to remove it.
Support. Single maintainer, no SLA, no commercial backing, effectively zero community. Treat it as a vendored utility rather than a supported dependency — assume we may own the code at some point, and keep the internal abstraction thin enough that forking is a half-day task.
Scaling. Negligible. The detector only runs on the exception path, so it has no effect on happy-path throughput or latency. At high write volume, though, the exception path itself is expensive (a failed INSERT plus exception construction); the package does not make retry-on-conflict cheap. For genuinely hot dedupe paths, prefer INSERT ... ON CONFLICT / INSERT IGNORE or a pre-check over throw-and-classify.
Failure modes.
Ramp-up. Low — an engineer can read the source in under an hour. The onboarding cost is understanding where conflict handling belongs in the domain, which is a design conversation, not a documentation one. Budget roughly a day of engineering time for adoption including tests, and plan an explicit review point at the next Laravel major upgrade to decide whether to drop the dependency in favor of the native exception.
How can I help you explore Laravel packages today?