PHPackages                             quellabs/objectquel - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. quellabs/objectquel

ActiveLibrary[Database &amp; ORM](/categories/database)

quellabs/objectquel
===================

A sophisticated ORM system with a unique query language and streamlined architecture

2.4.9(2w ago)02661MITPHPPHP &gt;=8.3

Since Jun 3Pushed 3w ago1 watchersCompare

[ Source](https://github.com/quellabs/objectquel)[ Packagist](https://packagist.org/packages/quellabs/objectquel)[ GitHub Sponsors](https://github.com/sponsors/quellabs)[ RSS](/packages/quellabs-objectquel/feed)WikiDiscussions main Synced today

READMEChangelog (10)Dependencies (81)Versions (147)Used By (1)

ObjectQuel
==========

[](#objectquel)

[![Latest Version](https://camo.githubusercontent.com/dc88e0d03716a85f6b11aed36a24585d02e529216285ec7a491de9f423208249/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7175656c6c6162732f6f626a6563747175656c2e737667)](https://packagist.org/packages/quellabs/objectquel)[![PHPStan](https://camo.githubusercontent.com/1bc07920f0d36e55c17e1d38b1caa132cc605f51a82b388c962870b9a747b898/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6c6576656c253230392d627269676874677265656e2e737667)](https://phpstan.org)[![License](https://camo.githubusercontent.com/074b89bca64d3edc93a1db6c7e3b1636b874540ba91d66367c0e5e354c56d0ea/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e737667)](LICENSE)

A domain-level query language and engine for PHP, with a full ORM attached. ObjectQuel's declarative syntax inspired by [QUEL](https://en.wikipedia.org/wiki/QUEL_query_languages) expresses entity queries above the table level — relationships, patterns, full-text search, and cross-source joins are first-class expressions, not raw SQL escapes. Supports MySQL, PostgreSQL, SQLite, and SQL Server.

```
$results = $entityManager->executeQuery("
    range of p is App\\Entity\\Product
    range of c is App\\Entity\\Category via p.categories
    retrieve (p, categoryName=c.name)
    where p.price < :maxPrice and c.active = true
    sort by p.name asc
", [
    'maxPrice' => 50.00
]);
```

The engine resolves entity relationships, decomposes the query into optimized SQL, and hydrates the results. You write intent; ObjectQuel handles the mechanics.

Installation
------------

[](#installation)

```
composer require quellabs/objectquel
```

Upgrading to 2.0
----------------

[](#upgrading-to-20)

Version 2.0 introduces breaking changes to the relationship annotation model:

- **`@OneToMany` is removed.** Replace it with `@InverseOf(targetEntity=..., relation="...")` on the owning entity's inverse collection property. `InverseOf` is a hydration instruction only — it does not define a relationship or generate a join.
- **Non-owning `@OneToOne` is removed.** The non-owning side of a OneToOne relationship should now be declared with `@InverseOf` instead.
- **`@OneToOne` is owning-side only.** Every `@OneToOne` annotation must hold the foreign key column.

Before:

```
// UserEntity
/** @Orm\OneToMany(targetEntity=PostEntity::class, mappedBy="user") */
public Collection $posts;
```

After:

```
// UserEntity
/** @Orm\InverseOf(targetEntity=PostEntity::class, relation="user") */
public CollectionInterface $posts;
```

Quick start
-----------

[](#quick-start)

```
use Quellabs\ObjectQuel\Configuration;
use Quellabs\ObjectQuel\EntityManager;

$config = new Configuration();
$config->setEntityNamespace('App\\Entity');
$config->setEntityPath(__DIR__ . '/src/Entity');

$entityManager = new EntityManager($config, $connection);

// Standard lookups
$product = $entityManager->find(Product::class, 101);
$active  = $entityManager->findBy(Product::class, ['active' => true]);

// ObjectQuel for anything more complex
$results = $entityManager->executeQuery("
    range of p is App\\Entity\\Product
    retrieve (p) where p.name = /^Tech/i
    sort by p.createdAt desc
    window 0 using window_size 10
");
```

What the query language can do that others can't
------------------------------------------------

[](#what-the-query-language-can-do-that-others-cant)

Most ORM query languages are SQL with different syntax. ObjectQuel's abstraction layer sits above SQL, which lets it do things that aren't possible in DQL, Eloquent, or raw query builders:

**Pattern matching and regex in where clauses:**

```
// Wildcard matching — no LIKE syntax needed
retrieve (p) where p.sku = "ABC*XYZ"

// Regex with flags
retrieve (p) where p.name = /^tech/i
```

The equivalent in Doctrine requires `$qb->expr()->like()` or a raw `REGEXP` call. In Eloquent you'd write `whereRaw('name REGEXP ?', [...])`. ObjectQuel treats patterns as first-class query expressions.

**Full-text search with boolean operators and weighting:**

```
retrieve (p) where search(p.description, "banana +pear -apple")
```

No raw SQL, no engine-specific syntax. The query engine translates this to the appropriate full-text implementation for your database.

**Hybrid data sources — database + JSON in one query:**

```
range of order is App\\Entity\\OrderEntity
range of product is json_source('external/product_catalog.json')
retrieve (order, product.name, product.manufacturer)
where order.productSku = product.sku and order.status = :status
sort by order.orderDate desc
```

ObjectQuel can join database entities with JSON files in a single query, applying inner, left, or cross joins based on context — the engine handles the cross-source matching. Neither Doctrine nor Eloquent can do this. You'd query the database, load the JSON separately, and merge results in PHP. ObjectQuel also supports JSONPath prefiltering to extract nested structures before the query runs, keeping memory usage low on large files.

**Existence checks as expressions:**

```
// In the retrieve clause
retrieve (p.name, hasOrders=ANY(o.orderId))

// In the where clause
retrieve (p) where ANY(o.orderId)
```

**Automatic query decomposition:**

Complex queries are split into optimized sub-tasks by the engine rather than sent as a single monolithic SQL statement. This means ObjectQuel can optimize execution paths that a single SQL query cannot express efficiently.

**Database dialect abstraction:**

Features like full-text search, regex matching, and window functions compile to the correct SQL for your target database. The same ObjectQuel query runs on MySQL, PostgreSQL, SQLite, and SQL Server without modification. Switching databases means changing the connection, not rewriting queries.

Comparison
----------

[](#comparison)

A multi-entity query with filtering and relationship traversal:

**ObjectQuel:**

```
$rs = $entityManager->executeQuery("
    range of o is App\\Entity\\Order
    range of c is App\\Entity\\Customer via o.customer
    retrieve (o, c.name) where o.createdAt > :since
    sort by o.createdAt desc
    window 0 using window_size 20
");

foreach($rs as $row) {
    ...
}
```

**Doctrine DQL:**

```
$results = $entityManager->createQuery(
    'SELECT o, c.name FROM App\\Entity\\Order o
     JOIN o.customer c
     WHERE o.createdAt > :since
     ORDER BY o.createdAt DESC'
)->setParameter('since', $since)
 ->setMaxResults(20)
 ->getResult();
```

**Eloquent:**

```
$results = Order::with('customer:id,name')
    ->where('created_at', '>', $since)
    ->orderByDesc('created_at')
    ->take(20)
    ->get();
```

The difference becomes more pronounced with regex filtering, existence checks, hybrid sources, and multi-relationship traversals — operations that require raw SQL or post-processing in other ORMs.

ORM capabilities
----------------

[](#orm-capabilities)

ObjectQuel is a full Data Mapper ORM, not just a query language:

- **Entity mapping** — annotation-based with `@Orm\Table`, `@Orm\Column`, and relationship annotations
- **Relationships** — OneToOne, ManyToOne, InverseOf (hydration target for inverse collections), ManyToMany (via bridge entities)
- **Unit of Work** — change tracking with persist and flush
- **Lazy loading** — configurable proxy generation with caching
- **Immutable entities** — for database views and read-only tables
- **Optimistic locking** — version-based concurrency control
- **Cascading** — configurable cascade operations across relationships
- **Lifecycle events** — pre/post persist, update, and delete via SignalHub
- **Custom repositories** — optional repository pattern with type-safe access
- **Indexing** — annotation-driven index management
- **Migrations** — database schema migrations powered by Phinx

CLI tooling
-----------

[](#cli-tooling)

ObjectQuel ships with Sculpt, a CLI tool for entity and schema management:

```
# Generate a new entity interactively
php bin/sculpt make:entity

# Reverse-engineer entities from an existing database table
php bin/sculpt make:entity-from-table

# Generate migrations from entity changes
php bin/sculpt make:migrations

# Run pending migrations
php bin/sculpt quel:migrate
```

`make:entity-from-table` is particularly useful when adopting ObjectQuel in an existing project — point it at your tables and get annotated entities without writing them by hand.

Framework integration
---------------------

[](#framework-integration)

ObjectQuel works standalone or with the [Canvas framework](https://canvasphp.com). The `quellabs/canvas-objectquel`package provides automatic service discovery, dependency injection, and Sculpt CLI integration within Canvas.

For other frameworks, configure the `EntityManager` directly — it has no framework dependencies.

Documentation
-------------

[](#documentation)

Full query language reference, entity mapping guide, and architecture docs: **[objectquel.com/docs](https://objectquel.com/docs)**

Support
-------

[](#support)

If ObjectQuel saves you time, consider [sponsoring development](https://github.com/sponsors/quellabs).

License
-------

[](#license)

MIT

###  Health Score

51

—

FairBetter than 95% of packages

Maintenance96

Actively maintained with recent releases

Popularity14

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity70

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~2 days

Total

144

Last Release

15d ago

Major Versions

1.12.0 → 2.0.02026-06-07

PHP version history (2 changes)1.0.75PHP &gt;=8.4

1.0.76PHP &gt;=8.3

### Community

Maintainers

![](https://www.gravatar.com/avatar/57e4ab872b3e37536367f2d26b192df3d3bb6a6a1cebec9a104d14a6d2ffe157?d=identicon)[noescom](/maintainers/noescom)

---

Top Contributors

[![quellabs](https://avatars.githubusercontent.com/u/7067695?v=4)](https://github.com/quellabs "quellabs (11 commits)")

---

Tags

databasedatabase-abstractiondatamapperentity-mappingobject-relational-mappingormquery-languageormentity-managerquery-languageObjectQuel

### Embed Badge

![Health badge](/badges/quellabs-objectquel/health.svg)

```
[![Health](https://phpackages.com/badges/quellabs-objectquel/health.svg)](https://phpackages.com/packages/quellabs-objectquel)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
