Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Rowcast Laravel Package

ascetic-soft/rowcast

Lightweight DataMapper over PDO for PHP 8.4+. Maps database rows to DTOs and back using reflection, with auto or explicit mapping, type conversion, and a fluent query builder featuring dialect-aware UPSERT.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

What it actually is. Rowcast is a framework-agnostic PHP 8.4 library (PDO + reflection) for mapping DTOs to and from database rows, with a fluent query builder and dialect-aware UPSERT. It is not a Laravel package: there is no service provider, facade, config file, publishable assets, or Artisan surface. In a Laravel codebase it is a parallel persistence path that sits beside Eloquent and the DB facade, not a replacement for either. Product framing should be "a low-level persistence utility we may consume in narrow places," not "an ORM alternative."

Architecture fit. Good fit where the codebase already treats domain objects as plain DTOs and wants reads/writes without model lifecycle baggage: bulk import/export, ETL, reporting read models, legacy-schema access, large batch writes. Poor fit for anything needing relationships, events/observers, soft deletes, global scopes, multi-tenant filtering, or model-level authorization — none of which exist here, and rebuilding them would defeat the purpose.

Positive quality signals. PHPStan level 9, Codecov, CI badge, make ci gate documented, dialect logic centralized in src/QueryBuilder/Dialect/, changelog and releases present, bilingual docs plus llms.txt, and unusually candid in-repo agent notes. The code discipline reads better than the adoption metrics suggest.

Integration feasibility. Mechanically trivial: composer require, construct Connection, construct DataMapper, bind both as singletons. Roughly half a day including a service provider you write yourself. The actual cost is convention-setting — mapping ownership, converter registry, save() vs upsert() policy — not installation.

Technical risk.

  • Bus factor 1 / zero adoption. 0 stars, 0 dependents means we would be the only known production user. No field-tested failure modes, no Stack Overflow corpus, no third-party tutorials. The opportunity score (12.01) is a proxy for that isolation, not for code quality.
  • PHP 8.4 floor. This is usually the gating item, not the package. If CI images, prod runtimes, or a shared library constraint the fleet to 8.2/8.3, adoption is blocked or forces an unrelated upgrade program.
  • Mutable Mapping. Explicitly documented as mutable and configured in place. This is a standing code-review tax and a footgun for shared instances across services.
  • save() is read-before-write. Two statements, a race window, and no conflict constraint required. upsert() is the efficient path but depends on dialect and schema. Teams will pick the wrong one without a written rule.
  • Dialect coverage. Only mysql, pgsql, sqlite are mapped; everything else silently falls back to GenericDialect. ILIKE/NOT ILIKE are Postgres-only — a portability trap if we test on Postgres and run on MySQL.
  • Performance is unquantified. Reflection-based extract/hydrate on hot paths with no published benchmarks. findAll materializes; iterateAll exists but streaming behavior needs verification against a real cursor.
  • Release date anomaly. The listed last release (2026-06-15) is future-dated relative to the rest of the signal set. Verify actual cadence, tags, and BC history on Packagist before relying on any of it.

Key questions for the maintainer/owner decision.

  1. Is this a maintained product or a personal library? What is the commit cadence and the path to 1.0?
  2. What is the BC policy pre/post-1.0, and is there a security disclosure process?
  3. Any published numbers for batch insert/upsert vs. raw PDO vs. Eloquent at 10k–100k rows?
  4. Is mapping/type-conversion stable enough to wrap behind our own interface, or is the API still moving?
  5. Any static state that breaks under Octane, long-running queue workers, or persistent connections?

Integration Approach

Stack fit. Works anywhere PDO does, which means zero coupling to the Laravel version — a genuine plus during framework upgrades. The trade is that we own the wiring: a ~30-line service provider binding Connection and DataMapper as singletons, plus config for DSN, nested-transaction default, and the converter registry.

Where to use it (and where not to).

Use case Fit Rationale
Bulk import / ETL / backfills Strong batchInsert/batchUpsert with automatic bind-parameter chunking (SQLite 999) inside one transaction is the core value
Reporting read models over legacy schemas Strong findAll/iterateAll + DTO hydration without inventing models
API response projections Moderate Avoids Eloquent overhead, but only worth a second persistence idiom if volume justifies it
Domain aggregate writes Poor No events, relationships, scopes, soft deletes, or concurrency control
Anything multi-tenant Poor No scoping mechanism; tenancy would be hand-rolled on every query

Migration path — strangler, per job, no big bang. Introduce Rowcast as a new path inside one bounded background job or one read-only endpoint. Keep Eloquent as the system of record for domain writes. Establish an explicit ownership rule: a given table is written by exactly one layer. Mixing Rowcast writes and Eloquent writes on the same aggregate without that rule is how stale-model bugs get born.

Wrap it. Put Rowcast behind an internal interface (e.g. BulkWriter, WarehouseReader) with the mapper injected privately. Given zero dependents and a single maintainer, this is the highest-leverage TPM decision in the whole assessment: it converts a vendor risk into a swap cost of a few days instead of a rewrite.

Compatibility decisions to make up front.

  • Runtime: confirm PHP 8.4 in CI and prod images before any code is written.
  • Transactions: nested/savepoint mode is opt-in. Pick one default for our environment and document the failure semantics.
  • Dialect: pin the target driver. If we test on Postgres, do not ship code paths using ILIKE to a MySQL deployment.
  • Converters: DateTimeConverter formats to UTC strings — that is an opinionated decision we are inheriting, not a neutral default. Validate JSON, bool (0/1), enum, and nullability behavior against our actual schema before trusting hydration.

Sequencing.

  1. Runtime readiness gate (PHP 8.4 in CI, images, and any shared library constraints).
  2. Pilot: one batch/ETL job, with a hard baseline (rows/sec, peak memory, error rate) against the current implementation and against raw PDO.
  3. Codify conventions: Mapping instances built once at setup and treated as immutable; a static-analysis or review rule banning in-place mutation; a written save() vs upsert() policy.
  4. Wire onBeforeQuery / onAfterQuery into the existing logging and metrics pipeline at adoption time.
  5. Only after the pilot is green, consider a second use case. Reassess vendor risk at six months or before a second team onboards.

Operational Impact

Maintenance. Tiny surface, zero runtime dependencies (PDO only), so dependency drift and CVE exposure are near zero. That is the good news. The bad news is that if upstream goes quiet, we own the bug fixes. Budget roughly 1–2 engineer-days per quarter as an ongoing stewardship tax, plus a named contingency: fork-and-vendor the repo internally if release cadence stalls.

Support. No vendor, no SLA, no commercial backing, community of effectively zero. Issues are best-effort. Name a specific owning team and a specific individual; "the platform team" is not an owner. In exchange, the documentation is better than typical for a zero-star project — bilingual docs, an llms.txt for AI-assisted development, and agent notes that describe CI order and code layout, which materially lowers the cost of internal fork maintenance.

Scaling. Horizontal scaling is a property of PDO and the database, not of this library. The library-specific scaling concerns are: result-set materialization in findAll (use iterateAll for large reads, and verify it is a true cursor rather than an eagerly built array); reflection overhead in tight hydrate/extract loops (measure, don't assume); and chunk sizing for batch operations, which governs bind-parameter limits and transaction size but not round-trip latency. Tune chunk sizes empirically per driver.

Failure modes to instrument and document.

  • Schema drift: renamed or dropped columns manifest as missing mapping or hydration errors, not graceful degradation.
  • Type coercion surprises: bool ↔ 0/1, JSON decode failures, timezone assumptions in the DateTime converter, non-nullable typed properties receiving NULL.
  • save() read-before-write races under concurrency; wrong choice between save() and upsert().
  • UPSERT semantics differing by dialect and silently depending on the presence of a conflict constraint.
  • Savepoint misuse in nested transactions leaving partial state that looks committed.
  • Name-converter surprises: class-name derivation produces UserDto → user_dtos, not users. Cheap to hit, embarrassing in production.
  • GenericDialect fallback masking unsupported-driver behavior instead of failing loudly.

Ramp-up. The API is small enough for a mid-level engineer to be productive in a day; the docs plus llms.txt accelerate that further. The real ramp is not the API but the conventions — mapping ownership, converter registry behavior, and the save/upsert policy — and none of the team will have production mileage on it. The pilot is the training, which is another argument for piloting on a non-critical background job rather than a customer-facing path. Onboarding cost is low; confidence cost is only paid down by running it.

Observability. The query event hooks (onBeforeQuery, onAfterQuery with duration and exception) are the substitute for Eloquent's event surface. They must be wired into existing logging/metrics during the pilot — retrofitting observability after an incident is the standard way small libraries become mysterious ones.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log
hsluv/hsluv
seampact/codegen
seampact/hooks
seampact/ir
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table