क्वेरी बिल्डर
EntityQueryBuilder is Weaver ORM's fluent query API. It wraps Doctrine DBAL with full entity awareness: results are automatically hydrated into entity objects, global scopes are applied, and soft-delete filters are managed transparently.
Getting a QueryBuilder
Obtain a builder from a repository via query(), or from EntityWorkspace via createQueryBuilder():
<?php
// From a repository (recommended)
$users = $this->userRepository
->query()
->where('is_active', true)
->get();
// From the workspace
use Weaver\ORM\EntityWorkspace;
use App\Entity\Post;
$posts = $this->workspace
->createQueryBuilder(Post::class)
->where('status', 'published')
->get();
SELECT clauses
select(...$columns)
Replace the SELECT list. Calling it again replaces the previous selection.
<?php
$users = $this->userRepository
->query()
->select('id', 'name', 'email')
->get();
addSelect(...$columns)
Append columns to the current SELECT list without replacing it.
<?php
$qb = $this->productRepository->query()->select('id', 'name', 'price');
if ($this->isGranted('ROLE_MANAGER')) {
$qb->addSelect('cost_price', 'supplier_id');
}
$products = $qb->get();
selectRaw($expression, $bindings = [])
Add a raw SQL expression to the SELECT list.
<?php
$orders = $this->orderRepository
->query()
->select('id', 'customer_id', 'total')
->selectRaw('DATEDIFF(NOW(), created_at) AS age_days')
->where('status', 'pending')
->get();
WHERE clauses
All where*() methods combine conditions with AND by default. Use orWhere*() variants to combine with OR.
where($column, $value) — equality
<?php
$user = $this->userRepository
->query()
->where('email', 'alice@example.com')
->first();
where($column, $operator, $value) — with operator
Supported operators: =, !=, <>, <, <=, >, >=, LIKE, NOT LIKE.
<?php
$expensive = $this->productRepository
->query()
->where('price', '>', 100)
->where('stock', '>', 0)
->get();
orWhere($column, $value)
<?php
$results = $this->userRepository
->query()
->where('role', 'admin')
->orWhere('role', 'moderator')
->get();
whereIn($column, $values)
<?php
$users = $this->userRepository
->query()
->whereIn('status', ['active', 'trial'])
->get();
whereNotIn($column, $values)
<?php
$posts = $this->postRepository
->query()
->whereNotIn('status', ['draft', 'archived'])
->get();
whereNull($column) / whereNotNull($column)
<?php
// Users who have never logged in
$neverLoggedIn = $this->userRepository
->query()
->whereNull('last_login_at')
->get();
// Users with a verified email
$verified = $this->userRepository
->query()
->whereNotNull('email_verified_at')
->get();
whereBetween($column, $min, $max)
<?php
$orders = $this->orderRepository
->query()
->whereBetween('total', 50, 500)
->get();
whereRaw($sql, $bindings = [])
<?php
$active = $this->subscriptionRepository
->query()
->whereRaw('expires_at > NOW() AND cancelled_at IS NULL')
->get();
// Always use bindings to avoid SQL injection
$results = $this->repository
->query()
->whereRaw('YEAR(created_at) = ?', [2024])
->get();
ORDER BY
orderBy($column, $direction = 'ASC')
<?php
$users = $this->userRepository
->query()
->orderBy('created_at', 'DESC')
->get();
orderByDesc($column)
Shorthand for orderBy($column, 'DESC').
<?php
$latest = $this->postRepository
->query()
->where('status', 'published')
->orderByDesc('published_at')
->limit(10)
->get();
orderByRaw($expression)
<?php
$products = $this->productRepository
->query()
->orderByRaw('FIELD(status, "featured", "active", "inactive")')
->get();
LIMIT and OFFSET
limit($n) / offset($n)
<?php
$page3 = $this->productRepository
->query()
->where('is_active', true)
->orderBy('name')
->limit(20)
->offset(40)
->get();
Eager loading
with(...$relations)
Load related entities in the same query (or a batched second query), avoiding N+1 problems.
<?php
$posts = $this->postRepository
->query()
->where('status', 'published')
->with('author', 'tags', 'comments')
->orderByDesc('published_at')
->get();
// Relations are already loaded — no extra queries
foreach ($posts as $post) {
echo $post->getAuthor()->getName();
}
Nested relations use dot notation:
<?php
$orders = $this->orderRepository
->query()
->with('customer', 'items.product')
->get();
Soft delete helpers
When an entity uses the #[SoftDelete] attribute, a global scope automatically filters out soft-deleted rows. Use these methods to override the default behaviour.
withTrashed() — include soft-deleted rows
<?php
$allPosts = $this->postRepository
->query()
->withTrashed()
->get();
onlyTrashed() — return only soft-deleted rows
<?php
$deleted = $this->postRepository
->query()
->onlyTrashed()
->orderByDesc('deleted_at')
->get();
withoutTrashed() — explicitly exclude soft-deleted rows
Useful inside a withTrashed() sub-scope to restore default filtering:
<?php
$active = $this->postRepository
->query()
->withoutTrashed()
->get();