🧱 Entities

Hector ORM offers two main approaches to manage entities within your project, each with its own benefits and trade-offs.

Tip: For advanced entity configuration (table mapping, column types, hidden fields, custom mappers), see Advanced configuration.

🪄 Magic Entity

Magic entities use PHP’s __get and __set magic methods to handle property access dynamically. This allows for concise classes without explicitly declaring properties.

Example

use Hector\Orm\Entity\MagicEntity;
use Hector\Orm\Collection\Collection;
use DateTimeInterface;

/**
 * @property int $id
 * @property string $firstname
 * @property string $lastname
 * @property string|null $email
 * @property DateTimeInterface $created_at
 * @property-read Collection<Post> $posts
 */
class User extends MagicEntity {}

$user = new User();
$user->firstname = 'Alice';
$user->lastname = 'Dupont';
echo $user->firstname; // Outputs "Alice"

Pros

  • Minimal boilerplate
  • Very flexible
  • Easy to prototype quickly

Cons

  • No native IDE autocompletion (partially mitigated with @property PHPDoc)
  • No static analysis
  • Harder to debug or refactor

🏛️ Classic Entity

Classic entities use explicitly declared class properties, giving better integration with IDEs and static analysis tools.

Example

use Hector\Orm\Entity\Entity;

class User extends Entity
{
    public string $firstname;
    public string $lastname;
}

$user = new User();
$user->firstname = 'Alice';
$user->lastname = 'Dupont';
echo $user->firstname; // Outputs "Alice"

Pros

  • IDE support (autocompletion, inspections)
  • Better for long-term maintenance
  • Easier to read and understand

Cons

  • More verbose
  • Less flexible for dynamic schemas

💾 Persisting Entities

Creating and Saving

To persist a new entity in the database, instantiate it, set its properties, and call the save() method:

$user = new User();
$user->firstname = 'Alice';
$user->lastname = 'Dupont';
$user->email = 'alice@example.com';

$user->save();

Cascade Save

Info: Since version 1.1

When your entity has relationships, you can persist them all at once using the cascade parameter. This will automatically save any related entities that have been modified or created:

$user->save(cascade: true);

Updating

$user = User::find(1);
$user->email = 'new-email@example.com';
$user->save();

// Check if entity has been modified
if ($user->isAltered()) {
    $user->save();
}

// Check specific column
if ($user->isAltered('email')) {
    // ...
}

Deleting

$user = User::find(1);
$user->delete();

Refreshing from Database

$user = User::find(1);
$user->firstname = 'Modified';
$user->refresh(); // Reloads original data from DB

Bulk Operations on Collections

Collections returned by the ORM support bulk operations, allowing you to apply actions to multiple entities at once:

$users = User::query()->where('active', false)->all();

// Save all entities in collection
$users->save();

// Delete all entities in collection
$users->delete();

// Refresh all entities from database
$users->refresh();

Cascade Save on Collections

Info: Since version 1.1

Like individual entities, collections also support cascade saving. This is useful when you need to persist a batch of entities along with their relationships:

$users->save(cascade: true);

🧩 Custom Mapper

You can also implement your own mapper to take full control over how entities are hydrated and managed.

See Advanced configuration for implementation details.

Use case

  • When you need full customization for hydration or entity behavior
  • When neither magic nor classic entities suit your needs

Last updated: Tue, 13 Jan 2026 11:08