Weave Code
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

Rowcast is a lightweight PDO DataMapper for PHP 8.4+. It maps DB rows to DTOs via reflection with auto/explicit mapping and type conversion, plus a fluent query builder with dialect-aware UPSERT.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture Fit

  • DTO-First Design: Aligns well with modern PHP architectures leveraging DTOs (e.g., Symfony, Laravel with API Platform). Eliminates ORM bloat while preserving type safety and separation of concerns.
  • Lightweight Abstraction: Avoids heavy ORMs (Doctrine, Eloquent) but retains query-building capabilities. Ideal for microservices, CLI tools, or performance-sensitive APIs.
  • Dialect Awareness: Supports PostgreSQL, MySQL, SQLite, and generic dialects, making it adaptable to multi-database environments (e.g., Laravel Forge deployments with mixed DBs).
  • Fluent Query Builder: Replaces raw PDO with a safer, more expressive API, reducing SQL injection risks and improving maintainability.

Integration Feasibility

  • Laravel Compatibility:
    • PDO Integration: Works seamlessly with Laravel’s built-in PDO connections (e.g., DB::connection()). Can wrap Laravel’s DatabaseManager for unified access.
    • Service Container: Register Connection and DataMapper as singletons in Laravel’s container, replacing Eloquent models for specific use cases (e.g., read-heavy APIs, batch processing).
    • Query Builder Replacement: Can replace Eloquent’s query builder for non-model operations (e.g., reporting, migrations, or third-party integrations).
  • Migration Path:
    • Incremental Adoption: Start with DataMapper for DTO hydration/extraction in services, then expand to replace Eloquent queries where appropriate.
    • Hybrid Approach: Use Rowcast for performance-critical paths (e.g., bulk inserts) while keeping Eloquent for traditional CRUD.
    • Custom Bindings: Extend Laravel’s DB facade to delegate to Rowcast’s Connection for specific tables.

Technical Risk

  • PHP 8.4 Dependency: Requires upgrading Laravel (v11+) or using a custom PHP runtime (e.g., Laravel Sail with PHP 8.4). Mitigate by:
  • ORM vs. DataMapper Mindset:
    • Risk of over-engineering for simple CRUD (e.g., replacing Eloquent models with DTOs + Rowcast).
    • Mitigation: Document clear boundaries (e.g., "Use Rowcast for batch operations; Eloquent for user-facing CRUD").
  • Type Safety Overhead:
    • DTOs require upfront type definitions, which may slow initial development.
    • Mitigation: Use PHP 8.2+ attributes or generators to auto-generate DTOs from database schemas (e.g., laravel-shift/database-to-dto).
  • Transaction Handling:
    • Nested transactions (savepoints) are opt-in and may not align with Laravel’s default transaction behavior.
    • Mitigation: Test savepoint behavior in Laravel’s transaction manager (e.g., DB::transaction()).

Key Questions

  1. Use Case Alignment:
    • Is Rowcast targeting performance bottlenecks (e.g., bulk operations, reporting) or replacing Eloquent entirely?
    • Example: "Will we use Rowcast for all queries, or only for specific tables (e.g., logs, analytics)?"
  2. DTO Strategy:
    • How will DTOs be managed? Manual definition, code generation, or a hybrid approach?
    • Example: "Will we use php-attributes to auto-generate DTOs from migrations?"
  3. Query Builder Migration:
    • Which Laravel query builder features are critical to retain (e.g., join, raw expressions)?
    • Example: "Does Rowcast support Laravel’s DB::raw() syntax for complex SQL?" (Answer: No; requires custom QueryBuilder extensions.)
  4. Testing Impact:
    • How will existing feature tests (e.g., Eloquent model tests) adapt to Rowcast?
    • Example: "Will we mock DataMapper in unit tests or rewrite integration tests?"
  5. Database Schema:
    • Are there schema constraints (e.g., composite keys, JSON columns) that Rowcast’s auto-mapping doesn’t handle?
    • Example: "How will Rowcast map ->where(['jsonb_column->>key' => 'value'])?" (Answer: Requires custom TypeConverter or QueryBuilder extension.)
  6. Error Handling:
    • How will database errors (e.g., unique constraint violations) be surfaced to Laravel’s exception handler?
    • Example: "Does Rowcast throw PDOException or wrap it in a custom exception?" (Answer: Throws PDOException; may need Laravel exception handler updates.)

Integration Approach

Stack Fit

  • Laravel Core:
    • Database Layer: Replace DB::statement(), DB::select(), and DB::table() calls with Rowcast’s Connection and DataMapper.
    • Eloquent: Use Rowcast for non-model operations (e.g., Model::query()->get()DataMapper::findAll(UserDto::class, [...])).
    • Migrations: Replace raw queries in migrations with Rowcast’s Connection for consistency.
  • Service Layer:
    • Inject DataMapper into services (e.g., UserService) for DTO-based operations.
    • Example:
      public function __construct(private DataMapper $mapper) {}
      public function createUser(UserDto $dto): UserDto {
          $this->mapper->insert('users', $dto);
          return $dto;
      }
      
  • API Layer:
    • Use Rowcast for DTO hydration in controllers (e.g., ResourceController::index()DataMapper::findAll(UserDto::class)).
    • Leverage iterateAll() for paginated APIs to avoid loading all results into memory.

Migration Path

  1. Phase 1: Proof of Concept
    • Replace 1–2 Eloquent-heavy endpoints with Rowcast (e.g., a reporting API).
    • Compare performance (e.g., taptapphp/bench for bulk inserts).
    • Validate DTO mapping (auto vs. explicit) for your schema.
  2. Phase 2: Core Integration
    • Database Layer:
      • Create a RowcastServiceProvider to bind Connection and DataMapper to Laravel’s container.
      • Example:
        $this->app->singleton(DataMapper::class, fn() =>
            new DataMapper(Connection::create(config('database.connections.mysql.dsn'), ...))
        );
        
    • Query Builder:
      • Extend Rowcast’s QueryBuilder to support Laravel-specific features (e.g., DB::raw).
      • Create a facade Rowcast::query() to mirror Laravel’s DB::query().
    • DTO Generation:
      • Use a tool like rector/rector to auto-convert Eloquent models to DTOs.
  3. Phase 3: Full Adoption
    • Replace Eloquent models with DTOs + Rowcast for new features.
    • Gradually migrate existing models to Rowcast (prioritize read-heavy or batch operations).
    • Deprecate Eloquent in favor of Rowcast for non-UI paths (e.g., CLI commands, queues).

Compatibility

  • Laravel-Specific Gaps:
    • Relationships: Rowcast lacks Eloquent’s hasOne, belongsTo. Mitigate by:
      • Using nested queries (e.g., DataMapper::findAll(UserDto::class, [...]) with joined DTOs).
      • Implementing custom RelationDto classes.
    • Observers/Events: Rowcast doesn’t support model events. Mitigate by:
      • Using Laravel’s Model observers alongside Rowcast for hybrid setups.
      • Triggering events manually in service layer (e.g., UserCreated::dispatch($dto)).
    • Scopes: Rowcast’s where clauses are more explicit. Mitigate by:
      • Creating reusable QueryBuilder instances with pre-defined conditions.
  • Database Features:
    • JSON/Array Columns: Rowcast supports JsonConverter out of the box.
    • Full-Text Search: Use Rowcast’s QueryBuilder with raw SQL (e.g., ->where('MATCH(body) AGAINST(?))').
    • Transactions: Rowcast’s nested transactions work with Laravel’s DB::transaction(), but savepoints may not roll back as expected in all cases.

Sequencing

  1. Start with Read Operations:
    • Replace Model::all(), Model::find(), and Model::where() with DataMapper::findAll()/findOne().
    • Example migration:
      // Before
      User::where('active', true)->get();
      
      // After
      $mapper->findAll(UserDto::class, ['active' => true]);
      
  2. Add Write Operations:
    • Replace Model::create(), Model::update() with DataMapper::insert()/update().
    • Example:
      // Before
      User::create(['email
      
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.
calmfox/watch-sylius
damienfern/grpc-symfony-bundle
atoolo/index-bundle
atoolo/genai-bundle
coprotoai/laravel-ticket
davidjln/llm-carbon-bundle
cryonighter/valid-request-bundle
coolms/taxonomy-bundle
coolms/field-bundle
articulate-orm/symfony
aaix/laravel-tall-architect
ephoto/akeneo-connector
emmanuelballery/eb-plantumlbundle
emielburgman/symfony-visitor-beacon
emielburgman/symfony-visit-storage
emielburgman/symfony-security-headers
emielburgman/symfony-log-viewer
emarref/xdebug-bundle
emarref/pubnub-bundle
elriseio/finance-money-bundle