From a82721cd22e724d3bb1121e227c42dc8a74ccdbd Mon Sep 17 00:00:00 2001 From: Thiago Cordeiro Date: Tue, 13 May 2025 12:19:38 +0200 Subject: [PATCH] Added readme --- LICENSE | 21 +++++ README.md | 129 +++++++++++++++++++++++++++++++ src/EntityRecordRepository.php | 6 +- tests/Fixtures/AddressMapper.php | 3 + 4 files changed, 156 insertions(+), 3 deletions(-) create mode 100644 LICENSE create mode 100644 README.md diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6cd3f3d --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 tcds-io + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..81a5279 --- /dev/null +++ b/README.md @@ -0,0 +1,129 @@ +# PHP ORM for PHP 8.4 + +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) + +A lightweight, type-safe Object-Relational Mapper (ORM) for modern PHP (8.4+), designed to be expressive and easy to +extend. It emphasizes strict typing and modern PHP features while providing a flexible mapping interface between +database rows and PHP objects. + +## 🚀 Installation + +Install via [Composer](https://getcomposer.org): + +```bash +composer require tcds-io/orm +``` + +## 🧠 Features + +- Typed mapping of database rows to PHP objects +- Support for Records and Entities +- Fine-grained control over columns (e.g. enums, dates, nullable values) +- Lazy-loading support +- PHP 8.4+ only, leveraging modern language features + +## 📦 Usage + +There are two main types of mappers: + +- `RecordMapper` — for mapping simple, immutable data records +- `EntityRecordMapper` — for mapping richer domain entities, with support for repositories or + lazy-loading + +### Record Mapper Example + +```php +/** + * @extends RecordMapper
+ */ +final class AddressMapper extends RecordMapper +{ + private IntegerColumn $id; + private StringColumn $street; + private FloatColumn $number; + private IntegerColumn $floor; + private BoolColumn $active; + private EnumColumn $type; + private DateTimeColumn $createdAt; + private DateTimeImmutableColumn $deletedAt; + + public function __construct() + { + $this->id = $this->integer('id', fn(Address $entry) => $entry->id); + $this->street = $this->string('street', fn(Address $entity) => $entity->street); + $this->number = $this->numeric('number', fn(Address $entity) => $entity->number); + $this->floor = $this->integer('floor', fn(Address $entity) => $entity->floor); + $this->active = $this->boolean('active', fn(Address $entity) => $entity->active); + $this->type = $this->enum(AddressType::class, 'type', fn(Address $entity) => $entity->type); + $this->createdAt = $this->datetime('created_at', fn(Address $entity) => $entity->createdAt); + $this->deletedAt = $this->datetimeImmutable('deleted_at', fn(Address $entity) => $entity->deletedAt); + } + + public function map(array $row): Address + { + return new Address( + id: $this->id->value($row), + street: $this->street->value($row), + number: $this->number->value($row), + floor: $this->floor->value($row), + active: $this->active->value($row), + type: $this->type->value($row), + createdAt: $this->createdAt->value($row), + deletedAt: $this->deletedAt->nullable($row), + ); + } +} +``` + +### Entity Mapper Example + +```php +/** + * @extends EntityRecordMapper + */ +final class UserMapper extends EntityRecordMapper +{ + public function __construct( + private readonly AddressRepository $addressRepository, + ) { + parent::__construct($this->string('id', fn(User $entity) => $entity->id)); + + $this->string('name', fn(User $entity) => $entity->name); + $this->date('date_of_birth', fn(User $entity) => $entity->dateOfBirth); + $this->integer('address_id', fn(User $entity) => $entity->address->id); + } + + public function map(array $row): User + { + return new User( + id: $row['id'], + name: $row['name'], + dateOfBirth: new DateTime($row['date_of_birth']), + address: lazyOf(Address::class, fn() => $this->addressRepository->loadById($row['address_id'])), + ); + } +} +``` + +### Nullable Support + +For nullable fields, use the `->nullable(...)` method on column definitions. This allows you to gracefully handle `NULL` +values in your database rows. + +## 🤝 Contributing + +Contributions are welcome! If you have ideas, find a bug, or want to improve the library, feel free to: + +- Fork the repo +- Create a new branch +- Submit a pull request + +Please follow PSR-12 coding standards and ensure tests pass before submitting changes. + +## 📄 License + +This project is open-sourced under the [MIT license](./LICENSE). + +--- + +Happy Mapping! 🎉 diff --git a/src/EntityRecordRepository.php b/src/EntityRecordRepository.php index e009a93..7863eaa 100644 --- a/src/EntityRecordRepository.php +++ b/src/EntityRecordRepository.php @@ -8,13 +8,13 @@ /** * @template EntryType - * @template ForeignKeyType + * @template PrimaryKeyType * @extends RecordRepository */ abstract class EntityRecordRepository extends RecordRepository { public function __construct( - /** @var EntityRecordMapper */ + /** @var EntityRecordMapper */ protected EntityRecordMapper $entityMapper, Connection $connection, string $table, @@ -23,7 +23,7 @@ public function __construct( } /** - * @param ForeignKeyType $id + * @param PrimaryKeyType $id * @return EntryType|null */ public function selectEntityById($id) diff --git a/tests/Fixtures/AddressMapper.php b/tests/Fixtures/AddressMapper.php index b820478..bd76d7b 100644 --- a/tests/Fixtures/AddressMapper.php +++ b/tests/Fixtures/AddressMapper.php @@ -13,6 +13,9 @@ use Tcds\Io\Orm\Column\StringColumn; use Tcds\Io\Orm\RecordMapper; +/** + * @extends RecordMapper
+ */ final class AddressMapper extends RecordMapper { private IntegerColumn $id;