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 Bundle Laravel Package

ascetic-soft/rowcast-bundle

Symfony bundle integrating ascetic-soft/rowcast connection and DataMapper, with optional rowcast-schema migrations/services and console commands. Supports SQL profiler integration, configurable DSN/auth/options, transactions, schema paths, and query profiling thresholds.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the Bundle:

    composer require ascetic-soft/rowcast-bundle
    

    Ensure RowcastBundle is auto-registered in config/bundles.php or add it manually.

  2. Configure the Bundle: Create config/packages/rowcast.yaml:

    rowcast:
      connection:
        dsn: '%env(DATABASE_DSN)%'
        username: '%env(DATABASE_USER)%'
        password: '%env(DATABASE_PASSWORD)%'
    
  3. First Use Case: Inject DataMapper into a service/repository and use it to fetch data:

    use AsceticSoft\Rowcast\DataMapper;
    
    final readonly class UserRepository {
        public function __construct(private DataMapper $mapper) {}
    
        public function findById(int $id): ?array {
            return $this->mapper->fetchOne('SELECT * FROM users WHERE id = :id', ['id' => $id]);
        }
    }
    
  4. Verify Connection: Use the rowcast:query console command to test connectivity:

    bin/console rowcast:query "SELECT 1"
    

Implementation Patterns

Core Workflows

1. Data Access Layer (DAL) Pattern

  • Repository Pattern: Use DataMapper to abstract database operations.
    final readonly class PostRepository {
        public function __construct(private DataMapper $mapper) {}
    
        public function findAllPublished(): array {
            return $this->mapper->fetchAll('SELECT * FROM posts WHERE published_at IS NOT NULL');
        }
    }
    
  • Type-Safe Hydration: Leverage Rowcast’s DataMapper with custom hydrators for complex objects.

2. Schema Management

  • Attribute-Based Schema: Define tables and columns using PHP attributes (requires ascetic-soft/rowcast-schema):
    #[Rowcast\Table(name: 'users')]
    class User {
        #[Rowcast\Column(type: 'integer', primary: true)]
        public int $id;
    
        #[Rowcast\Column(type: 'string', length: 255)]
        public string $email;
    }
    
    Configure in rowcast.yaml:
    rowcast:
      schema:
        path: '%kernel.project_dir%/src/Entity'
    
  • Schema Migrations: Generate and run migrations via CLI:
    bin/console rowcast:diff --dry-run  # Preview changes
    bin/console rowcast:make            # Generate migration files
    bin/console rowcast:migrate         # Apply migrations
    

3. Transaction Management

  • Nested Transactions: Enable in config (nest_transactions: true) for granular control:
    rowcast:
      connection:
        nest_transactions: true
    
  • Manual Transactions: Use Connection directly:
    $this->connection->beginTransaction();
    try {
        $this->mapper->execute('INSERT INTO users (...) VALUES (...)');
        $this->connection->commit();
    } catch (\Exception $e) {
        $this->connection->rollBack();
        throw $e;
    }
    

4. Query Building

  • Parameterized Queries: Always use named parameters to avoid SQL injection:
    $users = $this->mapper->fetchAll(
        'SELECT * FROM users WHERE status = :status',
        ['status' => 'active']
    );
    
  • Prepared Statements: Reuse prepared statements for performance:
    $stmt = $this->connection->prepare('SELECT * FROM users WHERE id = :id');
    $stmt->execute(['id' => 1]);
    $user = $stmt->fetch();
    

5. Integration with Symfony Services

  • Dependency Injection: Inject Connection or DataMapper into controllers/services:
    use AsceticSoft\Rowcast\DataMapper;
    
    final readonly class UserController {
        public function __construct(private DataMapper $mapper) {}
    
        public function index(): Response {
            $users = $this->mapper->fetchAll('SELECT * FROM users');
            return $this->render('users/index.html.twig', ['users' => $users]);
        }
    }
    
  • Event Listeners: Use Connection events (e.g., beforeQuery, afterQuery) for logging/auditing:
    $connection->addListener(new class implements ConnectionListenerInterface {
        public function beforeQuery(QueryEvent $event): void {
            // Log query details
        }
    });
    

Advanced Patterns

1. Custom Hydrators

  • Extend HydratorInterface to transform raw rows into domain objects:
    use AsceticSoft\Rowcast\Hydrator\HydratorInterface;
    
    final class UserHydrator implements HydratorInterface {
        public function hydrate(array $row): User {
            return new User(
                id: $row['id'],
                email: $row['email'],
                createdAt: new \DateTimeImmutable($row['created_at'])
            );
        }
    }
    
  • Register with DataMapper:
    $mapper->setHydrator(User::class, new UserHydrator());
    

2. Schema Extensions

  • Custom Parsers: Implement SchemaParserInterface for non-standard schema formats (e.g., JSON).
  • Platform-Specific Logic: Extend PlatformInterface for database-specific behaviors (e.g., PostgreSQL JSONB support).

3. Profiler Integration

  • Enable in dev environment (rowcast.yaml):
    rowcast:
      profiler:
        enabled: true
    
  • Access profiler data in Symfony’s toolbar or via RowcastDataCollector.

4. Testing

  • In-Memory Database: Use SQLite for tests with a temporary connection:
    $connection = new Connection(
        dsn: 'sqlite::memory:',
        username: '',
        password: ''
    );
    
  • Mocking: Mock Connection or DataMapper in unit tests:
    $mockConnection = $this->createMock(ConnectionInterface::class);
    $mockConnection->method('fetchAll')->willReturn([...]);
    

Gotchas and Tips

Common Pitfalls

1. Schema Configuration

  • Attribute Parser Requirement: If using path pointing to a directory in rowcast.schema.path, ensure ascetic-soft/rowcast-schema is installed and AttributeSchemaParser is available. Otherwise, fall back to file-based parsing.
  • Migration Table Conflicts: Ensure migration_table (default: _rowcast_migrations) doesn’t conflict with existing tables. Prefix with your app name if needed (e.g., myapp_rowcast_migrations).

2. Connection Management

  • DSN Format: Ensure the DSN matches your database driver (e.g., mysql://user:pass@localhost/db or pgsql://user:pass@localhost/db).
  • Transaction Isolation: Rowcast uses the database’s default isolation level. Explicitly set isolation if needed:
    $this->connection->execute('SET TRANSACTION ISOLATION LEVEL SERIALIZABLE');
    

3. Profiler Overhead

  • Dev-Only Flag: Always set profiler.enabled: false in production to avoid performance impact.
  • Query Limits: Configure max_queries to prevent memory issues in long-running requests:
    rowcast:
      profiler:
        max_queries: 100
    

4. Attribute-Based Schema

  • Class Discovery: Ensure all schema classes are autoloaded. Use composer dump-autoload if adding new classes.
  • Circular Dependencies: Avoid circular references in schema classes (e.g., User referencing Post which references User).

5. Console Command Quirks

  • Parameter Handling: For rowcast:query, use --param for each parameter to avoid ambiguity:
    bin/console rowcast:query "SELECT * FROM users WHERE id = :id" --param id=1
    
  • Output Formatting: Queries returning rows are auto-formatted as tables. For raw output, pipe to tools like jq or less.

Debugging Tips

1. Connection Issues

  • Test DSN: Use rowcast:query to verify connectivity:
    bin/console rowcast:query "SHOW TABLES"
    
  • Logs: Enable debug mode in Symfony (APP_DEBUG=1) to see connection errors.

2. Schema Errors

  • Dry Run: Always use rowcast:diff --dry-run before applying migrations.
  • Introspection: Use rowcast:status to check migration status:
    bin/console rowcast:status
    

3. Performance Bottlenecks

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.
aashan/pimcore-mcp-bundle
solution-forest/ai-kit-core
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin