All attributes live in MonkeysLegion\Entity\Attributes\.
Marks a class as a database entity.
#[Entity(table: 'products')]
class Product { ... }
| Param | Type | Default | Description |
|---|
$table | string | snake_case of class name | Database table name |
Marks the primary key property.
#[Id]
#[Field(type: 'unsignedBigInt', autoIncrement: true)]
public private(set) int $id;
Maps a property to a database column.
| Param | Type | Default | Description |
|---|
$type | string | — | Column type (see below) |
$length | ?int | null | String length |
$precision | ?int | null | Decimal precision |
$scale | ?int | null | Decimal scale |
$nullable | bool | false | Allow NULL |
$autoIncrement | bool | false | Auto-increment column |
$default | mixed | null | Default value |
Available types:
| Type | SQL Equivalent |
|---|
string | VARCHAR(length) |
text | TEXT |
int | INT |
unsignedBigInt | BIGINT UNSIGNED |
float | FLOAT |
decimal | DECIMAL(precision, scale) |
boolean | TINYINT(1) |
datetime | DATETIME |
date | DATE |
json | JSON |
binary | BLOB |
| Attribute | Target | Description |
|---|
#[Timestamps] | Class | Auto-manage created_at / updated_at columns |
#[SoftDeletes] | Class | Adds deleted_at column, filters deleted rows |
#[Fillable] | Property | Allow mass assignment |
#[Guarded] | Property | Block mass assignment |
#[Hidden] | Property | Exclude from serialization |
#[Virtual] | Property | Not stored in database (computed) |
#[Immutable] | Class | Prevent updates after creation |
#[Versioned] | Class | Optimistic locking via version column |
#[AuditTrail] | Class | Track entity changes |
#[Changeset] | Class | Track dirty fields |
#[Index(columns: ['slug'], name: 'idx_products_slug')]
#[Index(columns: ['email'], name: 'idx_users_email', unique: true)]
| Param | Type | Description |
|---|
$columns | string[] | Column names |
$name | string | Index name |
$unique | bool | Unique constraint (default: false) |
#[ManyToOne(target: Category::class, foreignKey: 'category_id')]
public ?Category $category;
| Param | Type | Description |
|---|
$target | class-string | Related entity class |
$foreignKey | string | Foreign key column in this table |
#[OneToMany(target: OrderItem::class, mappedBy: 'order_id')]
public array $items;
| Param | Type | Description |
|---|
$target | class-string | Related entity class |
$mappedBy | string | Foreign key column in the related table |
#[OneToOne(target: Profile::class, foreignKey: 'user_id')]
public ?Profile $profile;
#[ManyToMany(target: Tag::class)]
#[JoinTable(name: 'product_tags', joinColumn: 'product_id', inverseColumn: 'tag_id')]
public array $tags;
MonkeysLegion\Query\Query\QueryBuilder
Fluent SQL query builder with typed clause VOs, statement caching, and result caching.
$qb = $this->products->query();
$qb = (new QueryBuilder($connectionManager))->from('products');
| Property | Type | Description |
|---|
$bindingCount | int | Total parameter bindings in current query |
$connectionName | string | Resolved connection name |
$fromTable | string | Current FROM table |
$grammar | GrammarInterface | Active SQL grammar |
| Method | Signature | Description |
|---|
select() | (array $columns = ['*']): self | Set SELECT columns |
selectRaw() | (string $expr, array $bindings = []): self | Raw SELECT expression |
selectSub() | (Closure $callback, string $as): self | Sub-query as column |
distinct() | (): self | Apply DISTINCT |
| Method | Signature | Description |
|---|
from() | (string $table, ?string $alias = null): self | Set FROM table |
table() | (string $table, ?string $alias = null): self | Alias for from() |
| Method | Signature | Description |
|---|
join() | (string $table, Closure $callback, ?string $alias, JoinType $type): self | Callback-based JOIN |
joinOn() | (string $table, string $first, string $op, string $second, ...): self | Simple column-to-column JOIN |
leftJoin() | (string $table, callable $callback, ?string $alias): self | LEFT JOIN |
leftJoinOn() | (string $table, string $first, string $op, string $second, ...): self | Simple LEFT JOIN |
rightJoin() | (string $table, callable $callback, ?string $alias): self | RIGHT JOIN |
crossJoin() | (string $table, ?string $alias): self | CROSS JOIN |
fullJoin() | (string $table, Closure $callback, ?string $alias): self | FULL OUTER JOIN |
| Method | Signature | Description |
|---|
where() | (string $col, string $op, mixed $val): self | AND WHERE |
orWhere() | (string $col, string $op, mixed $val): self | OR WHERE |
whereIn() | (string $col, array $vals): self | WHERE IN |
orWhereIn() | (string $col, array $vals): self | OR WHERE IN |
whereNotIn() | (string $col, array $vals): self | WHERE NOT IN |
whereBetween() | (string $col, mixed $min, mixed $max): self | WHERE BETWEEN |
orWhereBetween() | (string $col, mixed $min, mixed $max): self | OR WHERE BETWEEN |
whereNotBetween() | (string $col, mixed $min, mixed $max): self | WHERE NOT BETWEEN |
whereNull() | (string $col): self | WHERE IS NULL |
orWhereNull() | (string $col): self | OR WHERE IS NULL |
whereNotNull() | (string $col): self | WHERE IS NOT NULL |
orWhereNotNull() | (string $col): self | OR WHERE IS NOT NULL |
whereExists() | (ExpressionInterface $sub): self | WHERE EXISTS |
whereGroup() | (Closure $callback, WhereBoolean $bool): self | Grouped WHERE (...) |
orWhereGroup() | (Closure $callback): self | Grouped OR WHERE (...) |
whereRaw() | (string $sql, array $bindings): self | Raw WHERE expression |
orWhereRaw() | (string $sql, array $bindings): self | Raw OR WHERE |
whereColumn() | (string $first, string $op, string $second, ...): self | Column-to-column comparison |
whereSubQuery() | (string $col, string $op, Closure $callback, ...): self | Sub-query WHERE |
whereDate() | (string $col, string $op, string $date): self | DATE() extraction |
whereJsonContains() | (string $col, mixed $value): self | JSON contains check |
| Method | Signature | Description |
|---|
orderBy() | (string $col, string $dir = 'ASC'): self | ORDER BY clause |
orderByDesc() | (string $col): self | ORDER BY ... DESC |
latest() | (string $col = 'created_at'): self | Latest first |
oldest() | (string $col = 'created_at'): self | Oldest first |
| Method | Signature | Description |
|---|
groupBy() | (string|array $columns): self | GROUP BY clause |
having() | (string $expr, array $bindings): self | HAVING clause |
orHaving() | (string $expr, array $bindings): self | OR HAVING |
| Method | Signature | Description |
|---|
limit() | (int $limit): self | Set LIMIT |
offset() | (int $offset): self | Set OFFSET |
forPage() | (int $page, int $perPage = 15): self | Pagination helper |
| Method | Signature | Description |
|---|
union() | (self $query, bool $all = false): self | UNION |
unionAll() | (self $query): self | UNION ALL |
withCte() | (string $name, Closure $cb, array $cols, bool $recursive): self | Common Table Expression |
| Method | Signature | Description |
|---|
lockForUpdate() | (bool $noWait = false): self | SELECT ... FOR UPDATE |
sharedLock() | (bool $noWait = false): self | SELECT ... FOR SHARE |
| Method | Signature | Description |
|---|
setCache() | (CacheInterface $cache, int $ttl = 60): self | Set PSR-16 result cache |
cache() | (int $ttl = 0, ?string $key = null): self | Enable caching for this query |
| Method | Returns | Description |
|---|
get() | list<array<string,mixed>> | All matching rows |
first() | ?array<string,mixed> | First row or null |
value(string $col) | mixed | Single column from first row |
pluck(string $col) | list<mixed> | Single column from all rows |
exists() | bool | Any rows match? |
count() | int | Row count |
sum(string $col) | float | SUM aggregate |
avg(string $col) | float | AVG aggregate |
min(string $col) | mixed | MIN aggregate |
max(string $col) | mixed | MAX aggregate |
| Method | Returns | Description |
|---|
insert(array $data) | int|string | Insert row, returns last insert ID |
update(array $data) | int | Update matching rows, returns affected count |
delete() | int | Delete matching rows, returns affected count |
upsert(array $data, array $uniqueKeys, array $updateCols) | int | Insert or update on conflict |
| Method | Signature | Description |
|---|
chunk() | (int $size, Closure $cb): void | Process rows in fixed-size batches |
chunkById() | (int $size, Closure $cb, string $col = 'id'): void | Chunk by cursor (no OFFSET cost) |
lazy() | (int $size = 1000): Generator | Yield rows one-by-one, memory-bounded |
| Method | Returns | Description |
|---|
compile() | array{sql: string, bindings: list<mixed>} | Compiled SQL + bindings |
toSql() | string | Compiled SQL string |
toDebugSql() | string | SQL with bindings inlined (⚠️ dev only) |
MonkeysLegion\Query\Repository\EntityRepository<TEntity>
Abstract base repository with CRUD, identity map, unit of work, batch loading, and pagination.
class ProductRepository extends EntityRepository
{
protected string $table = 'products';
protected string $entityClass = Product::class;
protected string $primaryKey = 'id';
}
| Method | Signature | Returns | Description |
|---|
find() | (int|string $id) | ?TEntity | Find by primary key |
findOrFail() | (int|string $id) | TEntity | Find or throw EntityNotFoundException |
findByIds() | (array $ids) | list<TEntity> | Batch find (single query) |
findOneBy() | (array $criteria) | ?TEntity | Find 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) |
| Method | Signature | Returns |
|---|
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} |
| Method | Signature | Description |
|---|
persist() | (object $entity): void | Schedule insert or update |
remove() | (object|int|string $entityOrId): void | Schedule deletion |
flush() | (): array{inserts, updates, deletes} | Execute all pending changes |
| Method | Signature | Returns | Description |
|---|
create() | (array $data) | TEntity | Hydrate + persist + flush |
update() | (int|string $id, array $data): void | — | Direct update (bypasses UoW) |
delete() | (int|string $id) | int | Direct delete (bypasses UoW) |
updateWhere() | (array $criteria, array $data) | int | Bulk update |
deleteWhere() | (array $criteria) | int | Bulk delete |
firstOrCreate() | (array $criteria, array $defaults) | TEntity | Find or create |
updateOrCreate() | (array $criteria, array $values) | TEntity | Upsert entity |
refresh() | (object $entity) | TEntity | Reload from DB |
| Method | Signature | Returns |
|---|
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 |
| Method | Signature | Description |
|---|
chunk() | (int $size, Closure $cb, array $criteria, array $orderBy): void | Process in batches |
| Method | Signature | Description |
|---|
with() | (array $relations): static | Set relations to eager-load (returns clone) |
| Method | Signature | Description |
|---|
query() | (): QueryBuilder | Fresh builder with global scopes applied |
withoutGlobalScope() | (string $name): static | Disable a specific global scope |
withoutGlobalScopes() | (): static | Disable ALL global scopes |
scope() | (string $name, mixed ...$args): static | Apply a named scope |
| Method | Signature | Description |
|---|
clear() | (): void | Reset identity map & unit of work |
getIdentityMap() | (): IdentityMap | Access identity map (debug/testing) |