Skip to content

# Micro ORM 6.0 - Major Release #25

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 26 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
a104cf5
Add minor changes
byjg Mar 23, 2025
37bf984
Replace SqlObject by SqlStatement
byjg Mar 24, 2025
5ab7491
Fix tests
byjg Mar 24, 2025
d32643b
Change MapFromDbToInstanceHandler.php
byjg Mar 24, 2025
d701109
Documentation
byjg Mar 24, 2025
171a4b5
Add UpdateConstraintInterface.php
byjg Mar 24, 2025
725a8e3
Add UpdateConstraintInterface.php
byjg Mar 24, 2025
84a41c3
Fix Psalm issues.
byjg Mar 24, 2025
07d3ee7
Merge branch 'master' into 6.0
byjg Mar 24, 2025
a9a0cbb
Remove deprecations; Clean up code;
byjg Mar 24, 2025
7eff5bb
Add documentation
byjg Mar 24, 2025
088807e
Add documentation
byjg Mar 25, 2025
fb54a4c
Create ObserverEvent.php
byjg Mar 26, 2025
f425143
Change MapperFunctions.php
byjg Mar 27, 2025
f0b8ce6
Remove Deprecations
byjg Mar 27, 2025
22fa468
Fix Namespace
byjg Mar 27, 2025
e326eb9
update documentation
byjg Mar 27, 2025
8591d1a
Fix Repository::setBeforeUpdate and Repository::setBeforeInsert
byjg Mar 27, 2025
5d189c6
Add beforeUpdate and beforeInsert to the table attribute.
byjg Mar 27, 2025
1740758
Refactor data handling and documentation
byjg Mar 28, 2025
f7bfe57
Update Documentation.
byjg Mar 30, 2025
7a7d767
Merge branch 'master' into 6.0
byjg May 22, 2025
58b1e4f
Fix tests to use SqlStatement instead of SqlObject
byjg May 22, 2025
60ce725
Refactor query logic and add support for HAVING clause.
byjg May 31, 2025
45ccf74
Merge branch 'master' into 6.0
byjg Aug 15, 2025
e9c1b37
Replace `SqlObject` with `SqlStatement` in tests and update method us…
byjg Aug 15, 2025
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
3 changes: 2 additions & 1 deletion .github/workflows/phpunit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@ jobs:
strategy:
matrix:
php-version:
- "8.4"
- "8.3"
- "8.2"
- "8.1"

steps:
- uses: actions/checkout@v4
- run: composer install
- run: ./vendor/bin/phpunit
- run: ./vendor/bin/psalm
- run: ./vendor/bin/phpunit

Documentation:
if: github.ref == 'refs/heads/master'
Expand Down
28 changes: 28 additions & 0 deletions .gitpod.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
tasks:
- name: Run Composer
command: |
composer install

image: byjg/gitpod-image:latest

jetbrains:
phpstorm:
vmoptions: '-Xmx4g'
plugins:
- com.github.copilot
- com.intellij.kubernetes
- com.intellij.mermaid
- ru.adelf.idea.dotenv
- org.toml.lang

vscode:
extensions:
- ikappas.composer
- hbenl.test-adapter-converter
- hbenl.vscode-test-explorer
- felixfbecker.php-debug
- neilbrayfield.php-docblocker
- bmewburn.vscode-intelephense-client
- getpsalm.psalm-vscode-plugin
- SonarSource.sonarlint-vscode
- recca0120.vscode-phpunit
35 changes: 35 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug current Script in Console",
"type": "php",
"request": "launch",
"program": "${file}",
"cwd": "${fileDirname}",
"port": 9003,
"runtimeArgs": [
"-dxdebug.start_with_request=yes"
],
"env": {
"XDEBUG_MODE": "debug,develop",
"XDEBUG_CONFIG": "client_port=${port}"
}
},
{
"name": "PHPUnit Debug",
"type": "php",
"request": "launch",
"program": "${workspaceFolder}/vendor/bin/phpunit",
"cwd": "${workspaceFolder}",
"port": 9003,
"runtimeArgs": [
"-dxdebug.start_with_request=yes"
],
"env": {
"XDEBUG_MODE": "debug,develop",
"XDEBUG_CONFIG": "client_port=${port}"
}
}
]
}
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ $result = $repository->getByQuery($query);
* [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)
* [The Model Attributes](docs/model.md)
* [The Repository Class](docs/repository.md)

## Advanced Topics

Expand All @@ -166,6 +168,7 @@ $result = $repository->getByQuery($query);
* [Using FieldAlias](docs/using-fieldalias.md)
* [Tables without auto increments fields](docs/tables-without-auto-increment-fields.md)
* [Using With Recursive SQL Command](docs/using-with-recursive-sql-command.md)
* [Update Constraints](docs/update-constraints.md)

## Install

Expand Down Expand Up @@ -198,4 +201,4 @@ flowchart TD
```

----
[Open source ByJG](http://opensource.byjg.com)
[Open source ByJG](http://opensource.byjg.com)
10 changes: 5 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@
"prefer-stable": true,
"minimum-stability": "dev",
"require": {
"php": ">=8.1 <8.4",
"php": ">=8.1 <8.5",
"ext-json": "*",
"byjg/anydataset-db": "^5.0"
"byjg/anydataset-db": "^6.0"
},
"require-dev": {
"phpunit/phpunit": "^9.6",
"byjg/cache-engine": "^5.0",
"vimeo/psalm": "^5.9"
"phpunit/phpunit": "^10.5|^11.5",
"byjg/cache-engine": "^6.0",
"vimeo/psalm": "^5.9|^6.2"
},
"suggest": {
"ext-curl": "*",
Expand Down
75 changes: 74 additions & 1 deletion docs/active-record.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
---
sidebar_position: 7
---

# Active Record

Active Record is the M in MVC - the model - which is the layer of the system responsible
Expand All @@ -16,7 +20,7 @@ e.g.:

```php
<?php
[TableAttribute('my_table')]
#[TableAttribute(tableName: 'my_table')]
class MyClass
{
// Add the ActiveRecord trait to enable the Active Record
Expand Down Expand Up @@ -84,6 +88,17 @@ foreach ($myClassList as $myClass) {
}
```

### Get all records

```php
<?php
// Get all records (paginated, default is page 0, limit 50)
$myClassList = MyClass::all();

// Get page 2 with 20 records per page
$myClassList = MyClass::all(2, 20);
```

### Delete a record

```php
Expand All @@ -110,6 +125,33 @@ $myClass->refresh();
### Update a model from another model or array

```php
<?php
// Get a record
$myClass = MyClass::get(1);

// Update from array
$myClass->fill(['someProperty' => 789]);

// Update from another model
$anotherModel = MyClass::new(['someProperty' => 789]);
$myClass->fill($anotherModel);

// Save changes
$myClass->save();
```

### Convert to array

```php
<?php
$myClass = MyClass::get(1);

// Convert to array (excluding null values)
$array = $myClass->toArray();

// Convert to array (including null values)
$array = $myClass->toArray(true);
```

### Using the `Query` class

Expand All @@ -121,3 +163,34 @@ $query = MyClass::joinWith('other_table');
// Execute the query
$myClassList = MyClass::query($query);
```

### Get table name

```php
<?php
$tableName = MyClass::tableName();
```

### Custom mapper configuration

By default, the Active Record uses the class attributes to discover the mapper configuration.
You can override this behavior by overriding the `discoverClass` method.

```php
<?php
class MyClass
{
use ActiveRecord;

// Override the default mapper discovery
protected static function discoverClass(): string|Mapper
{
// Return a custom mapper
return new Mapper(
self::class,
'custom_table',
['id']
);
}
}
```
126 changes: 120 additions & 6 deletions docs/auto-discovering-relationship.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
---
sidebar_position: 8
---

# Auto Discovering Relationship

The `FieldAttribute` has a parameter `parentTable` that is used to define the parent table of the field. This is used in
Expand All @@ -12,14 +16,14 @@ You can use the `parentTable` parameter in the `FieldAttribute` to define the pa

```php
<?php
#[TableAttribute('table1')]
#[TableAttribute(tableName: 'table1')]
class Class1
{
#[FieldAttribute(primaryKey: true)]
public ?int $id;
}

#[TableAttribute('table2')]
#[TableAttribute(tableName: 'table2')]
class Class2
{
#[FieldAttribute(primaryKey: true)]
Expand All @@ -33,16 +37,19 @@ $repository1 = new Repository($dbDriver, Class1::class);
$repository2 = new Repository($dbDriver, Class2::class);
```

This will automatically create the relationship between `table1` and `table2`.
This will automatically create the relationship between `table1` and `table2` through the ORM system's internal
relationship registry.

## Generating Queries with Relationships

To generate the SQL with the relationship you can use the `ORM` static class:
To generate the SQL query with the relationship, you can use the `ORM` static class:

```php
<?php
$query = ORM::getQueryInstance("table1", "table2");
```

The command above will return a query object similar to:
The command above will return a query object with the appropriate join, equivalent to:

```php
<?php
Expand All @@ -51,8 +58,115 @@ $query = Query::getInstance()
->join('table2', 'table2.id_table1 = table1.id');
```

## Queries with Multiple Tables

You can also create queries with multiple joined tables by passing more table names:

```php
<?php
$query = ORM::getQueryInstance("table1", "table2", "table3");
```

The ORM will automatically discover the path to connect these tables if relationships have been defined.

## Manual Relationship Definition

If you need to define relationships manually (without using attributes), you can use the `addRelationship` method:

```php
<?php
ORM::addRelationship("table1", "table2", "id_table1", "id");
```

This defines a relationship where `table2.id_table1` is a foreign key that references `table1.id`.

You can also use Mapper objects:

```php
<?php
$mapper1 = new Mapper(Class1::class);
$mapper2 = new Mapper(Class2::class);

ORM::addRelationship($mapper1, $mapper2, "id_table1");
```

In this case, the primary key will be automatically determined from the first mapper.

## Getting Relationship Information

You can get information about relationships between tables:

```php
<?php
// Get relationship keys
$relationships = ORM::getRelationship("table1", "table2");

// Get detailed relationship data
$relationshipData = ORM::getRelationshipData("table1", "table2");
```

### Return Value of getRelationship

The `ORM::getRelationship()` method returns an array of relationship keys that define the path between the specified
tables. Each key in the array is a string formatted as "tableA,tableB" which identifies a specific relationship in the
internal relationship registry.

For example, if you call:

```php
$relationships = ORM::getRelationship("table1", "table2");
```

It might return something like:

```php
["table1,table2"]
```

If there are multiple tables involved in a path (like when finding relationships between more distant tables), it would
return all the relationship keys in the path, like:

```php
["table1,intermediateTable", "intermediateTable,table2"]
```

These keys identify the relationships in the internal registry and are used to retrieve the actual relationship details.

### Return Value of getRelationshipData

The `ORM::getRelationshipData()` method returns the actual detailed relationship information for the tables. It takes
the keys returned by `getRelationship()` and retrieves the corresponding relationship data objects.

The method returns an array of relationship data objects, where each object contains:

- `parent`: The parent table name
- `child`: The child table name
- `pk`: The primary key in the parent table
- `fk`: The foreign key in the child table

For example:

```php
$relationshipData = ORM::getRelationshipData("table1", "table2");
```

Might return:

```php
[
[
"parent" => "table1",
"child" => "table2",
"pk" => "id",
"fk" => "id_table1"
]
]
```

This detailed information is used internally when automatically constructing joins in queries between the tables.

## Limitations

- This feature does not support multiple relationships between the same tables
- Primary keys with two or more fields are not supported.
- Primary keys with two or more fields are not fully supported for auto-relationship discovery

Loading