solophp/abstract-repository

An abstract repository implementation for PHP applications, providing a standardized way to interact with database tables using the Solo Query Builder.

v1.3.0 2025-06-04 11:26 UTC

This package is auto-updated.

Last update: 2025-06-04 11:28:28 UTC


README

Version License

An abstract repository implementation for PHP applications, providing a standardized way to interact with database tables using the Solo Query Builder.

Installation

composer require solophp/abstract-repository

Features

  • Unified Repository Pattern: Standardized interface for database operations
  • CRUD Operations: Complete set of Create, Read, Update, Delete methods
  • Aggregation Functions: Built-in support for SUM, COUNT, AVG, MAX, MIN operations
  • Bulk Operations: Mass update and delete operations with WHERE conditions
  • Filtering and Sorting: Flexible criteria-based querying with sorting options
  • Soft Delete Support: Optional soft deletion with restore capabilities
  • Pagination: Built-in support for paginated results
  • Record Synchronization: Efficient bulk operations for synchronizing datasets
  • Transaction Support: Atomic operations for data integrity

Basic Usage

Creating a Repository

<?php

namespace App\Repositories;

use Solo\AbstractRepository\Repository;
use Solo\QueryBuilder\Facade\Query;

class UserRepository extends Repository
{
    // Optionally enable soft deletes
    protected bool $softDeletes = true;

    // Override primary key if not 'id'
    protected string $primaryKey = 'user_id';
    
    public function __construct(Query $queryBuilder)
    {
        parent::__construct($queryBuilder, 'users');
    }
    
    // Add your custom repository methods here
    public function findActiveUsers(): array
    {
        return $this->getBy(['status' => 'active']);
    }
}

Basic Operations

// Instantiate your repository
$userRepo = new UserRepository($queryBuilder);

// Get by ID
$user = $userRepo->getById(123);

// Get all records
$allUsers = $userRepo->getAll();

// Create a new record
$userId = $userRepo->insert([
    'name' => 'John Doe',
    'email' => 'john@example.com',
    'created_at' => date('Y-m-d H:i:s')
]);

// Insert multiple records
$affectedRows = $userRepo->insertBatch([
    ['name' => 'John Doe', 'email' => 'john@example.com'],
    ['name' => 'Jane Smith', 'email' => 'jane@example.com']
]);

// Update a record
$userRepo->update(123, [
    'name' => 'Jane Smith',
    'updated_at' => date('Y-m-d H:i:s')
]);

// Update multiple records by criteria
$affectedRows = $userRepo->updateBy(
    ['status' => 'pending'],
    ['status' => 'active', 'updated_at' => date('Y-m-d H:i:s')]
);

// Delete a record (soft delete if enabled)
$userRepo->deleteById(123);

// Delete multiple records by criteria (soft delete if enabled)
$userRepo->deleteBy(['status' => 'suspended']);

Advanced Usage

Querying with Criteria

// Find records with criteria
$admins = $userRepo->getBy([
    'role' => 'admin',
    'status' => 'active'
]);

// With ordering
$sortedAdmins = $userRepo->getBy(
    ['role' => 'admin'],
    ['last_login' => 'DESC']
);

// With pagination
$paginatedUsers = $userRepo->getBy(
    ['status' => 'active'],
    ['created_at' => 'DESC'],
    10,  // limit per page
    2    // page number
);

// Find first matching record
$firstAdmin = $userRepo->getFirstBy(['role' => 'admin']);

Aggregation Functions

// Calculate sum of a field
$totalSales = $orderRepo->sumBy(['status' => 'completed'], 'total');

// Count records matching criteria
$activeUsers = $userRepo->countBy(['status' => 'active']);
$pendingOrders = $orderRepo->countBy(['status' => 'pending']);

// Calculate average
$avgOrderValue = $orderRepo->avgBy(['status' => 'completed'], 'total');
$avgUserAge = $userRepo->avgBy(['role' => 'customer'], 'age');

// Find maximum value
$highestOrder = $orderRepo->maxBy(['user_id' => 123], 'total');
$latestLogin = $userRepo->maxBy(['status' => 'active'], 'last_login');

// Find minimum value
$smallestOrder = $orderRepo->minBy(['user_id' => 123], 'total');
$earliestUser = $userRepo->minBy([], 'created_at');

// Real-world examples
$monthlyRevenue = $orderRepo->sumBy([
    'status' => 'paid',
    'created_at >=' => '2025-05-01'
], 'total');

$unverifiedPayments = $paymentRepo->countBy(['is_verified' => 0]);

Working with Soft Deletes

// Soft delete (if enabled)
$userRepo->deleteById(123);

// Force delete (bypasses soft delete)
$userRepo->forceDeleteById(123);

// Soft delete multiple records (if enabled)
$userRepo->deleteBy(['status' => 'suspended']);

// Force delete multiple records (bypasses soft delete)
$userRepo->forceDeleteBy(['status' => 'suspended']);

// Get soft-deleted records
$deletedUsers = $userRepo->getDeleted();

// Restore a soft-deleted record
$userRepo->restoreById(123);

Record Existence Checks

// Check if record exists with the email
$exists = $userRepo->exists(['email' => 'john@example.com']);

// Check if another record exists with the same email (excluding current record)
$duplicateExists = $userRepo->existsExcluding(
    ['email' => 'john@example.com'],
    123
);

Bulk Operations

// Update multiple records matching criteria
$userRepo->updateBy(
    ['department' => 'IT', 'status' => 'active'],
    ['bonus_eligible' => true, 'updated_at' => date('Y-m-d H:i:s')]
);

// Delete multiple records matching criteria (respects soft deletes)
$userRepo->deleteBy(['status' => 'suspended']);

// Force delete multiple records (bypasses soft deletes)
$userRepo->forceDeleteBy(['status' => 'banned']);

// Synchronize collections
// - Creates new records
// - Updates existing records
// - Deletes records not in the newUsers array
$userRepo->syncById($newUsers, $currentUsers);

Transaction Support

// Start a transaction manually
$userRepo->beginTransaction();
try {
    $userId = $userRepo->insert(['name' => 'New User']);
    $userRepo->update($userId, ['profile_created' => true]);
    $userRepo->commit();
} catch (\Throwable $e) {
    $userRepo->rollBack();
    throw $e;
}

// Or use the convenient withTransaction method
$userRepo->withTransaction(function(Repository $repo) {
    // Multiple operations in a single transaction
    $userId = $repo->insert(['name' => 'New User']);
    $repo->update($userId, ['profile_created' => true]);
    // ...
});

Available Methods

Read Operations

Method Description
getById(int $id): ?object Get a record by primary key
getAll(): array Get all records
getFirstBy(array $criteria, ?array $orderBy = null): ?object Get first record matching criteria
getBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $page = null): array Get records matching criteria
getDeleted(): array Get soft-deleted records

Write Operations

Method Description
insert(array $data): ?int Insert a single record and return its ID
insertBatch(array $records): int Insert multiple records and return affected rows
update(int $id, array $data): int Update a record
updateBy(array $criteria, array $data): int Update records matching criteria
deleteById(int $id): int Delete a record (soft if enabled)
forceDeleteById(int $id): int Force delete a record
deleteBy(array $criteria): int Delete records matching criteria (soft if enabled)
forceDeleteBy(array $criteria): int Force delete records matching criteria
restoreById(int $id): int Restore a soft-deleted record
syncById(array $newRecords, array $currentRecords): void Synchronize records

Aggregation Operations

Method Description
sumBy(array $criteria, string $field): float Calculate sum of a field
countBy(array $criteria): int Count records matching criteria
avgBy(array $criteria, string $field): float Calculate average value of a field
maxBy(array $criteria, string $field): mixed Find maximum value of a field
minBy(array $criteria, string $field): mixed Find minimum value of a field

Utility Methods

Method Description
exists(array $criteria): bool Check if a record exists
existsExcluding(array $criteria, int $excludeId): bool Check if a record exists, excluding ID

Transaction Methods

Method Description
beginTransaction(): bool Start a transaction
commit(): bool Commit the current transaction
rollBack(): bool Roll back the current transaction
inTransaction(): bool Check if a transaction is currently active
withTransaction(callable $callback): mixed Execute callback within transaction

Requirements

  • PHP 8.2 or higher
  • solophp/query-builder package

License

The MIT License (MIT). Please see License File for more information.