Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ MicroORM implements **Martin Fowler's enterprise patterns**:

- **[Repository](https://martinfowler.com/eaaCatalog/repository.html)**: Mediates between domain and data mapping layers
- **[Data Mapper](https://martinfowler.com/eaaCatalog/dataMapper.html)**: Separates domain objects from database tables
- **[Active Record](https://martinfowler.com/eaaCatalog/activeRecord.html)**: Wraps database rows with domain logic (
alternative approach)
- **[Active Record](https://martinfowler.com/eaaCatalog/activeRecord.html)**: Wraps database rows with domain logic,
as a facade over the two above

You can choose the pattern that best fits your application: use Repository + Data Mapper for complex domains, or Active
Record for simpler CRUD-focused applications.
They are layers, not alternatives. The **Mapper** (Data Mapper) and the **Repository** are always there; the
`ActiveRecord` trait is a facade that creates them for the model. What you choose is where the mapping lives (a `Mapper`
object or attributes on the model) and where the persistence calls live (a repository or the model itself). See
[Choosing a Pattern](docs/patterns.md).

These are the key components:

Expand Down Expand Up @@ -178,6 +180,7 @@ $result = $repository->getByQuery($query);
## Basics

* [Defining the Model](docs/getting-started-model.md)
* [Choosing a Pattern](docs/patterns.md)
* [Querying the Database](docs/querying-the-database.md)
* [Updating the database](docs/updating-the-database.md)
* [Using the Mapper Object](docs/using-mapper-object.md)
Expand Down
30 changes: 5 additions & 25 deletions docs/active-record.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 5
sidebar_position: 7
---

# Active Record
Expand All @@ -25,18 +25,9 @@ business objects whose data requires persistent storage to a database.
- Provides methods like `save()`, `delete()`, `get()`, `all()`, etc.
- Database operations are directly available on the domain object

**When to use Active Record vs Repository/Data Mapper:**

| Aspect | Active Record | Repository + Data Mapper |
|--------------------|------------------------------------|-------------------------------|
| **Complexity** | Simple, straightforward | More complex, more layers |
| **Best for** | Simple domains, CRUD-heavy apps | Complex domain logic, DDD |
| **Coupling** | Domain objects know about database | Domain objects are pure |
| **Learning curve** | Lower | Higher |
| **Testability** | Harder (objects tied to DB) | Easier (dependency injection) |

💡 **Tip**: For simple applications or prototypes, Active Record is perfect. For complex domain logic or when following
Domain-Driven Design principles, prefer Repository + Data Mapper.
Behind the trait is the same `Repository` and `Mapper` used everywhere else in MicroORM:
the trait creates them for the model on the first call. To compare Active Record with
the repository approach, see [Choosing a Pattern](patterns.md).

## How to Use Active Record

Expand Down Expand Up @@ -266,15 +257,4 @@ The Active Record pattern offers several advantages:

## When to Use Active Record vs. Repository

Both patterns have their place in application development:

- **Use Active Record when**:
- You prefer a simpler, more direct approach
- Your application has straightforward database operations
- You want to reduce the number of classes in your codebase

- **Use Repository when**:
- You need more control over database operations
- Your application requires complex queries
- You prefer a more explicit separation between models and database operations
- You're implementing a domain-driven design approach
See [Choosing a Pattern](patterns.md). Both can be used in the same application.
79 changes: 5 additions & 74 deletions docs/architecture-layers.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 20
sidebar_position: 24
---

# Architecture Layers: Infrastructure vs Domain
Expand All @@ -9,79 +9,9 @@ sidebar_position: 20
The MicroORM is designed with a clear separation between **Infrastructure Layer** (raw data access) and **Domain Layer
** (entity-aware operations). Understanding when to use each layer is crucial for writing maintainable code.

## Architectural Foundation

This architecture follows **Martin Fowler's Enterprise Application Architecture patterns**, specifically:

### Repository Pattern

> *"Mediates between the domain and data mapping layers using a collection-like interface for accessing domain
objects."*
>
> — Martin
> Fowler, [Patterns of Enterprise Application Architecture](https://martinfowler.com/eaaCatalog/repository.html)

**In MicroORM:**

- The `Repository` class acts as a collection-like interface
- Isolates domain objects from database access code
- Provides a clean separation between domain and data layers
- Handles entity lifecycle (CRUD operations)

### Data Mapper Pattern

> *"A layer of software that separates the in-memory objects from the database. Its responsibility is to transfer data
between the two and also to isolate them from each other."*
>
> — Martin
> Fowler, [Patterns of Enterprise Application Architecture](https://martinfowler.com/eaaCatalog/dataMapper.html)

**In MicroORM:**

- The `Mapper` class defines the relationship between entities and database tables
- Translates between domain objects (entities) and database rows
- Keeps domain objects independent of database schema
- Allows field name mapping, transformations, and type conversions

**Why These Patterns Matter:**

- ✅ **Testability**: Mock repositories without touching the database
- ✅ **Flexibility**: Change database schema without changing domain objects
- ✅ **Separation of Concerns**: Domain logic stays pure, database logic stays isolated
- ✅ **Maintainability**: Clear boundaries make code easier to understand and modify

### Active Record Pattern (Alternative Approach)

> *"An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on
that data."*
>
> — Martin
> Fowler, [Patterns of Enterprise Application Architecture](https://martinfowler.com/eaaCatalog/activeRecord.html)

**In MicroORM:**

- The `ActiveRecord` trait provides static methods like `get()`, `save()`, `delete()`, etc.
- Each Active Record instance represents a single database row
- Database operations are directly available on domain objects
- Simpler than Repository/Data Mapper for straightforward CRUD applications

**Pattern Comparison:**

```
Repository + Data Mapper Active Record
├─ Domain objects are pure ├─ Domain objects know about DB
├─ More layers/complexity ├─ Fewer layers/simpler
├─ Better for complex domains ├─ Better for simple domains
├─ Easier to test (DI) ├─ Harder to test (static methods)
└─ More flexible └─ More convenient
```

**Choosing Your Pattern:**

- Use **Active Record** for: Simple apps, prototypes, CRUD-heavy applications
- Use **Repository + Data Mapper** for: Complex domain logic, Domain-Driven Design, enterprise applications

See [Active Record Documentation](active-record.md) for detailed usage examples.
This page is about using the `Repository` versus building a `Query` directly. For the
Data Mapper, Repository and Active Record patterns, and how to choose between them, see
[Choosing a Pattern](patterns.md).

## The Two Layers

Expand Down Expand Up @@ -381,6 +311,7 @@ operations where entity transformation is not needed or not desired.

## See Also

- [Choosing a Pattern](patterns.md)
- [Repository Documentation](repository.md)
- [Querying the Database](querying-the-database.md)
- [Query Building](query-build.md)
2 changes: 1 addition & 1 deletion docs/auto-discovering-relationship.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 8
sidebar_position: 9
---

# Auto Discovering Relationship
Expand Down
2 changes: 1 addition & 1 deletion docs/cache.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 11
sidebar_position: 12
---

# Caching the Results
Expand Down
2 changes: 1 addition & 1 deletion docs/common-traits.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 11
sidebar_position: 13
---

# Common Traits for Timestamp Fields
Expand Down
3 changes: 2 additions & 1 deletion docs/comparison-with-other-orms.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 21
sidebar_position: 25
---

# MicroORM vs Other ORMs
Expand Down Expand Up @@ -1154,6 +1154,7 @@ features.

## See Also

- [Choosing a Pattern](patterns.md)
- [Architecture Layers](architecture-layers.md)
- [Active Record](active-record.md)
- [Repository Documentation](repository.md)
2 changes: 1 addition & 1 deletion docs/controlling-the-data.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 13
sidebar_position: 15
---

# Controlling the data
Expand Down
17 changes: 8 additions & 9 deletions docs/getting-started-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,17 +94,16 @@ _See also: [Controlling the data](controlling-the-data.md) for advanced mapping_

### When to use each Mapper or Attribute?

The `Mapper` class is more flexible and can be used in any PHP version. Use cases:
Both produce the same `Mapper`. The difference is where the mapping lives:

* You have a legacy class and cannot change it
* You don't want change the Model class
* You can't change the Model class
* **Attributes** put the mapping on the model. It is the simplest option when you own the
class.
* **A `Mapper` object** keeps the mapping outside the model, so the model has no
database knowledge. Use it for legacy or third-party classes you cannot change, or
when the domain model must stay free of database concerns.

The `Attributes` is more simple and can be used in PHP 8.3 or later. Use cases:

* You want a more simple way to define the Model
* You want to use the latest PHP features
* You can have a more simple way to define the Model
See [Choosing a Pattern](patterns.md) for how this combines with the Repository and
Active Record.

### Example

Expand Down
2 changes: 1 addition & 1 deletion docs/mapper-functions.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 14
sidebar_position: 17
---

# Mapper Functions
Expand Down
2 changes: 1 addition & 1 deletion docs/model-attribute.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 5
sidebar_position: 6
---

# The Model Attributes
Expand Down
2 changes: 1 addition & 1 deletion docs/observers.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 12
sidebar_position: 14
---

# Observers
Expand Down
Loading
Loading