-
Notifications
You must be signed in to change notification settings - Fork 0
Exceptions
The ORM layer raises a small hierarchy of typed exceptions. They are organised into two families: model errors (operation gates, configuration issues) and entity errors (magic-method misuse).
\Exception
├── InitORM\ORM\Exceptions\ModelException
│ ├── WritableException ← create() / createBatch() with $writable = false
│ ├── ReadableException ← read() with $readable = false
│ ├── UpdatableException ← update() / updateBatch() with $updatable = false
│ └── DeletableException ← delete() with $deletable = false
│
└── InitORM\ORM\Exceptions\EntityException
← Entity::__call() with an unrecognised method name
The Model also propagates BadMethodCallException (from __call forwarding failures) and any exception raised by the layers below: DatabaseException, SQLExecuteException, ConnectionException, QueryBuilderException, DataMapperException.
The umbrella for all ORM-layer model errors. Direct instantiation is reserved for configuration problems detected at construction:
class Bad extends \InitORM\ORM\Model
{
protected string $schema = 'x';
protected bool $useSoftDeletes = true;
// $deletedField missing
}
new Bad();
// ModelException: "App\Model\Bad has $useSoftDeletes enabled but $deletedField is not configured."Catch ModelException when you want to handle every ORM-layer "the model said no" outcome regardless of which specific gate / invariant tripped.
class Configuration extends \InitORM\ORM\Model
{
protected string $schema = 'configuration';
protected bool $writable = false;
}
(new Configuration())->create(['k' => 'v']);
// WritableException: "App\Model\Configuration is not writable."Fires from:
Model::create()Model::createBatch()
Always before any SQL is built.
class AuditLog extends \InitORM\ORM\Model
{
protected string $schema = 'audit_log';
protected bool $readable = false;
}
(new AuditLog())->read();
// ReadableException: "App\Model\AuditLog is not readable."Fires from Model::read().
class Events extends \InitORM\ORM\Model
{
protected string $schema = 'events';
protected bool $updatable = false;
}
(new Events())->update([...]);
// UpdatableExceptionFires from Model::update() and Model::updateBatch().
class ReadOnly extends \InitORM\ORM\Model
{
protected string $schema = 'configuration';
protected bool $deletable = false;
}
(new ReadOnly())->delete([...]);
// DeletableExceptionFires from Model::delete().
$entity = new \InitORM\ORM\Entity();
$entity->doSomething();
// EntityException: 'Unknown entity method "doSomething".'Entity::__call provides a default implementation for the get{Column}Attribute / set{Column}Attribute family. Any other method name raises EntityException.
use InitORM\ORM\Exceptions\WritableException;
try {
$config->create([...]);
} catch (WritableException $e) {
// Handle the specific "this model can't be written" case.
}use InitORM\ORM\Exceptions\ModelException;
try {
$config->create([...]);
} catch (ModelException $e) {
// Catches WritableException, ReadableException, UpdatableException,
// DeletableException, and any direct ModelException (e.g. config invariants).
}use InitORM\ORM\Exceptions\ModelException;
use InitORM\ORM\Exceptions\EntityException;
try {
// …
} catch (ModelException | EntityException $e) {
// All ORM-layer failures, but not the underlying Database / DBAL / QB ones.
}Model::__call raises BadMethodCallException when the requested method does not exist anywhere in the chain (model, Database, builder). The original DatabaseException is chained as the previous exception:
try {
$posts->thisDoesNotExist();
} catch (\BadMethodCallException $e) {
echo $e->getMessage(); // 'Method "App\Model\Posts::thisDoesNotExist" does not exist.'
echo $e->getPrevious()::class; // 'InitORM\Database\Exceptions\DatabaseException'
}The model layer is a thin wrapper. Most "real" failures come from below:
| Exception | When |
|---|---|
InitORM\Database\Exceptions\DatabaseException |
Database-layer configuration / state problems. |
InitORM\Database\Exceptions\DatabaseInvalidArgumentException |
Invalid args passed to Database methods. |
InitORM\DBAL\Connection\Exceptions\ConnectionException |
PDO cannot connect. |
InitORM\DBAL\Connection\Exceptions\SQLExecuteException |
Prepare / execute fails. |
InitORM\DBAL\DataMapper\Exceptions\DataMapperException |
DataMapper used before a statement is set. |
InitORM\QueryBuilder\Exceptions\QueryBuilderException |
Builder used incorrectly (e.g. missing required clause). |
InitORM\QueryBuilder\Exceptions\QueryBuilderInvalidArgumentException |
Builder called with an invalid logical operator etc. |
These propagate unchanged through the model — they are documented in the corresponding sibling wiki.
Model exception messages always contain the fully qualified class name of the offending model:
App\Model\Configuration is not writable.
App\Model\AuditLog is not readable.
App\Model\Events is not updatable.
App\Model\ReadOnly is not deletable.
App\Model\Bad has $useSoftDeletes enabled but $deletedField is not configured.
This makes it trivial to grep logs and locate the misuse without consulting the stack trace.
try {
$config->create([...]);
} catch (\Exception $e) {
// swallows everything — connection errors, syntax errors, …
}Too broad. Pick the narrowest class that captures the error you actually want to handle.
try {
$posts->update([...]);
} catch (\Throwable) {
// Pretend nothing happened.
}If a gate refuses an operation or an SQL execute fails, the caller probably needs to know. Re-throw or log, do not silently drop.
- Permission Gates — when each gate exception fires.
-
Defining Models — the constructor-time
ModelExceptioncases. -
Entities — when
EntityExceptionfires. - Database wiki — Exceptions — lower-layer exceptions.
InitORM ORM · MIT · maintained by Muhammet ŞAFAK · part of the InitORM stack
Getting Started
Models
Entities
Cross-Cutting
Reference
Upgrading
Project