📦 Marketplace⭐ GitHub
API Referencev2.0

Entity, Query Builder & Repository


Table of Contents


Entity Attributes

All attributes live in MonkeysLegion\Entity\Attributes\.

#[Entity]

Marks a class as a database entity.

#[Entity(table: 'products')]
class Product { ... }
ParamTypeDefaultDescription
$tablestringsnake_case of class nameDatabase table name

#[Id]

Marks the primary key property.

#[Id]
#[Field(type: 'unsignedBigInt', autoIncrement: true)]
public private(set) int $id;

#[Field]

Maps a property to a database column.

ParamTypeDefaultDescription
$typestringColumn type (see below)
$length?intnullString length
$precision?intnullDecimal precision
$scale?intnullDecimal scale
$nullableboolfalseAllow NULL
$autoIncrementboolfalseAuto-increment column
$defaultmixednullDefault value

Available types:

TypeSQL Equivalent
stringVARCHAR(length)
textTEXT
intINT
unsignedBigIntBIGINT UNSIGNED
floatFLOAT
decimalDECIMAL(precision, scale)
booleanTINYINT(1)
datetimeDATETIME
dateDATE
jsonJSON
binaryBLOB

Behavioral Attributes

AttributeTargetDescription
#[Timestamps]ClassAuto-manage created_at / updated_at columns
#[SoftDeletes]ClassAdds deleted_at column, filters deleted rows
#[Fillable]PropertyAllow mass assignment
#[Guarded]PropertyBlock mass assignment
#[Hidden]PropertyExclude from serialization
#[Virtual]PropertyNot stored in database (computed)
#[Immutable]ClassPrevent updates after creation
#[Versioned]ClassOptimistic locking via version column
#[AuditTrail]ClassTrack entity changes
#[Changeset]ClassTrack dirty fields

Index Attribute

#[Index(columns: ['slug'], name: 'idx_products_slug')]
#[Index(columns: ['email'], name: 'idx_users_email', unique: true)]
ParamTypeDescription
$columnsstring[]Column names
$namestringIndex name
$uniqueboolUnique constraint (default: false)

Relationship Attributes

#[ManyToOne]

#[ManyToOne(target: Category::class, foreignKey: 'category_id')]
public ?Category $category;
ParamTypeDescription
$targetclass-stringRelated entity class
$foreignKeystringForeign key column in this table

#[OneToMany]

#[OneToMany(target: OrderItem::class, mappedBy: 'order_id')]
public array $items;
ParamTypeDescription
$targetclass-stringRelated entity class
$mappedBystringForeign key column in the related table

#[OneToOne]

#[OneToOne(target: Profile::class, foreignKey: 'user_id')]
public ?Profile $profile;

#[ManyToMany]

#[ManyToMany(target: Tag::class)]
#[JoinTable(name: 'product_tags', joinColumn: 'product_id', inverseColumn: 'tag_id')]
public array $tags;

QueryBuilder

MonkeysLegion\Query\Query\QueryBuilder

Fluent SQL query builder with typed clause VOs, statement caching, and result caching.

Construction

// Via repository (recommended)
$qb = $this->products->query();

// Standalone
$qb = (new QueryBuilder($connectionManager))->from('products');

Properties (PHP 8.4 Hooks)

PropertyTypeDescription
$bindingCountintTotal parameter bindings in current query
$connectionNamestringResolved connection name
$fromTablestringCurrent FROM table
$grammarGrammarInterfaceActive SQL grammar

SELECT

MethodSignatureDescription
select()(array $columns = ['*']): selfSet SELECT columns
selectRaw()(string $expr, array $bindings = []): selfRaw SELECT expression
selectSub()(Closure $callback, string $as): selfSub-query as column
distinct()(): selfApply DISTINCT

FROM

MethodSignatureDescription
from()(string $table, ?string $alias = null): selfSet FROM table
table()(string $table, ?string $alias = null): selfAlias for from()

JOIN

MethodSignatureDescription
join()(string $table, Closure $callback, ?string $alias, JoinType $type): selfCallback-based JOIN
joinOn()(string $table, string $first, string $op, string $second, ...): selfSimple column-to-column JOIN
leftJoin()(string $table, callable $callback, ?string $alias): selfLEFT JOIN
leftJoinOn()(string $table, string $first, string $op, string $second, ...): selfSimple LEFT JOIN
rightJoin()(string $table, callable $callback, ?string $alias): selfRIGHT JOIN
crossJoin()(string $table, ?string $alias): selfCROSS JOIN
fullJoin()(string $table, Closure $callback, ?string $alias): selfFULL OUTER JOIN

WHERE

MethodSignatureDescription
where()(string $col, string $op, mixed $val): selfAND WHERE
orWhere()(string $col, string $op, mixed $val): selfOR WHERE
whereIn()(string $col, array $vals): selfWHERE IN
orWhereIn()(string $col, array $vals): selfOR WHERE IN
whereNotIn()(string $col, array $vals): selfWHERE NOT IN
whereBetween()(string $col, mixed $min, mixed $max): selfWHERE BETWEEN
orWhereBetween()(string $col, mixed $min, mixed $max): selfOR WHERE BETWEEN
whereNotBetween()(string $col, mixed $min, mixed $max): selfWHERE NOT BETWEEN
whereNull()(string $col): selfWHERE IS NULL
orWhereNull()(string $col): selfOR WHERE IS NULL
whereNotNull()(string $col): selfWHERE IS NOT NULL
orWhereNotNull()(string $col): selfOR WHERE IS NOT NULL
whereExists()(ExpressionInterface $sub): selfWHERE EXISTS
whereGroup()(Closure $callback, WhereBoolean $bool): selfGrouped WHERE (...)
orWhereGroup()(Closure $callback): selfGrouped OR WHERE (...)
whereRaw()(string $sql, array $bindings): selfRaw WHERE expression
orWhereRaw()(string $sql, array $bindings): selfRaw OR WHERE
whereColumn()(string $first, string $op, string $second, ...): selfColumn-to-column comparison
whereSubQuery()(string $col, string $op, Closure $callback, ...): selfSub-query WHERE
whereDate()(string $col, string $op, string $date): selfDATE() extraction
whereJsonContains()(string $col, mixed $value): selfJSON contains check

ORDER BY

MethodSignatureDescription
orderBy()(string $col, string $dir = 'ASC'): selfORDER BY clause
orderByDesc()(string $col): selfORDER BY ... DESC
latest()(string $col = 'created_at'): selfLatest first
oldest()(string $col = 'created_at'): selfOldest first

GROUP BY / HAVING

MethodSignatureDescription
groupBy()(string|array $columns): selfGROUP BY clause
having()(string $expr, array $bindings): selfHAVING clause
orHaving()(string $expr, array $bindings): selfOR HAVING

LIMIT / OFFSET

MethodSignatureDescription
limit()(int $limit): selfSet LIMIT
offset()(int $offset): selfSet OFFSET
forPage()(int $page, int $perPage = 15): selfPagination helper

UNION / CTE

MethodSignatureDescription
union()(self $query, bool $all = false): selfUNION
unionAll()(self $query): selfUNION ALL
withCte()(string $name, Closure $cb, array $cols, bool $recursive): selfCommon Table Expression

Locking

MethodSignatureDescription
lockForUpdate()(bool $noWait = false): selfSELECT ... FOR UPDATE
sharedLock()(bool $noWait = false): selfSELECT ... FOR SHARE

Caching

MethodSignatureDescription
setCache()(CacheInterface $cache, int $ttl = 60): selfSet PSR-16 result cache
cache()(int $ttl = 0, ?string $key = null): selfEnable caching for this query

Execution — Read

MethodReturnsDescription
get()list<array<string,mixed>>All matching rows
first()?array<string,mixed>First row or null
value(string $col)mixedSingle column from first row
pluck(string $col)list<mixed>Single column from all rows
exists()boolAny rows match?
count()intRow count
sum(string $col)floatSUM aggregate
avg(string $col)floatAVG aggregate
min(string $col)mixedMIN aggregate
max(string $col)mixedMAX aggregate

Execution — Write

MethodReturnsDescription
insert(array $data)int|stringInsert row, returns last insert ID
update(array $data)intUpdate matching rows, returns affected count
delete()intDelete matching rows, returns affected count
upsert(array $data, array $uniqueKeys, array $updateCols)intInsert or update on conflict

Execution — Batch

MethodSignatureDescription
chunk()(int $size, Closure $cb): voidProcess rows in fixed-size batches
chunkById()(int $size, Closure $cb, string $col = 'id'): voidChunk by cursor (no OFFSET cost)
lazy()(int $size = 1000): GeneratorYield rows one-by-one, memory-bounded

Debugging

MethodReturnsDescription
compile()array{sql: string, bindings: list<mixed>}Compiled SQL + bindings
toSql()stringCompiled SQL string
toDebugSql()stringSQL with bindings inlined (⚠️ dev only)

EntityRepository

MonkeysLegion\Query\Repository\EntityRepository<TEntity>

Abstract base repository with CRUD, identity map, unit of work, batch loading, and pagination.

Setup

class ProductRepository extends EntityRepository
{
    protected string $table = 'products';
    protected string $entityClass = Product::class;
    protected string $primaryKey = 'id'; // override for UUID/custom PK
}

Finder Methods

MethodSignatureReturnsDescription
find()(int|string $id)?TEntityFind by primary key
findOrFail()(int|string $id)TEntityFind or throw EntityNotFoundException
findByIds()(array $ids)list<TEntity>Batch find (single query)
findOneBy()(array $criteria)?TEntityFind by arbitrary criteria
findBy()(array $criteria, array $orderBy, ?int $limit, ?int $offset)list<TEntity>Find with filtering & pagination
findAll()(array $orderBy = [])list<TEntity>All entities (use carefully)

Pagination

MethodSignatureReturns
paginate()(int $page = 1, int $perPage = 15)array{data, total, page, perPage, lastPage}
cursorPaginate()(?int|string $cursor, int $perPage, string $column)array{data, nextCursor, hasMore}

Persistence (Unit of Work)

MethodSignatureDescription
persist()(object $entity): voidSchedule insert or update
remove()(object|int|string $entityOrId): voidSchedule deletion
flush()(): array{inserts, updates, deletes}Execute all pending changes

Convenience DML

MethodSignatureReturnsDescription
create()(array $data)TEntityHydrate + persist + flush
update()(int|string $id, array $data): voidDirect update (bypasses UoW)
delete()(int|string $id)intDirect delete (bypasses UoW)
updateWhere()(array $criteria, array $data)intBulk update
deleteWhere()(array $criteria)intBulk delete
firstOrCreate()(array $criteria, array $defaults)TEntityFind or create
updateOrCreate()(array $criteria, array $values)TEntityUpsert entity
refresh()(object $entity)TEntityReload from DB

Aggregates

MethodSignatureReturns
count()(array $criteria = [])int
exists()(array $criteria)bool
sum()(string $col, array $criteria = [])float
avg()(string $col, array $criteria = [])float
min()(string $col, array $criteria = [])mixed
max()(string $col, array $criteria = [])mixed
pluck()(string $col, ?string $key, array $criteria)list|array

Batch Processing

MethodSignatureDescription
chunk()(int $size, Closure $cb, array $criteria, array $orderBy): voidProcess in batches

Eager Loading

MethodSignatureDescription
with()(array $relations): staticSet relations to eager-load (returns clone)

Scopes

MethodSignatureDescription
query()(): QueryBuilderFresh builder with global scopes applied
withoutGlobalScope()(string $name): staticDisable a specific global scope
withoutGlobalScopes()(): staticDisable ALL global scopes
scope()(string $name, mixed ...$args): staticApply a named scope

Identity Map

MethodSignatureDescription
clear()(): voidReset identity map & unit of work
getIdentityMap()(): IdentityMapAccess identity map (debug/testing)