Files
pinecore/.claude/architecture/orm.md
2026-04-06 18:47:11 +03:00

81 lines
3.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ORM (MongoDB)
## Атрибуты
| Атрибут | Применяется к | Описание |
|---|---|---|
| `#[Collection(name: 'users')]` | класс entity | Имя коллекции MongoDB |
| `#[Id]` | свойство | Кастомное поле `id` (строка), НЕ MongoDB `_id` |
| `#[Field]` | свойство | Обычное поле; имя в MongoDB = имя свойства |
| `#[Field(name: 'x')]` | свойство | Поле с другим именем в MongoDB |
| `#[Embedded]` | свойство | Вложенный объект (не Entity, просто класс) |
| `#[EmbeddedList]` | свойство | Массив вложенных объектов |
| `#[ForEntity(Foo::class)]` | класс репозитория | Связывает репозиторий с entity |
## Объявление Entity
```php
#[Collection(name: 'users')]
final class User implements MongoEntity
{
public function __construct(
#[Id] public readonly string $id,
#[Field] public readonly string $email,
#[Field] public readonly ?string $name = null,
// массив string[] — BSONArray конвертируется автоматически
#[Field] public readonly array $roles = [],
) {}
}
```
- `#[Id]` хранится в документе как поле `id` (не `_id`)
- MongoDB `_id` остаётся нативным ObjectId, пинекор его игнорирует
- `array` поля (в т.ч. `string[]`) — `BSONArray` конвертируется в PHP array прозрачно
- Если `$id === ''` при `persist()`, генерируется новый ID через `IdGenerator`
## Объявление репозитория
```php
#[ForEntity(User::class)]
final class UserRepository extends AbstractMongoRepository
{
// Публичный типизированный метод — не override protect persist()
public function save(User $user): User
{
return $this->persist($user);
}
public function findByEmail(string $email): ?User
{
return $this->findOneWhere(['email' => $email]);
}
}
```
## AbstractMongoRepository (`src/Orm/AbstractMongoRepository.php`)
Инжектируется через DI: `Database`, `MongoHydrator`, `IdGenerator`.
| Метод | Описание |
|---|---|
| `persist(object $entity): object` | upsert по полю `id`; если `id === ''`, генерирует новый |
| `findById(string $id): ?object` | поиск по полю `id` |
| `findOneWhere(array $filter): ?object` | произвольный MongoDB filter |
| `delete(string $id): void` | deleteOne по полю `id` |
| `collection(string $entityClass): Collection` | MongoDB\Collection для entity |
| `entityClass(): string` | читает `#[ForEntity]`, кешируется статически |
## MongoHydrator (`src/Orm/MongoHydrator.php`)
- `hydrate(string $class, array|BSONDocument $doc): object` — BSONDocument/array → typed entity через named constructor args
- `dehydrate(object $entity): array` — entity → array для MongoDB
- Рекурсивно обрабатывает `#[Embedded]` и `#[EmbeddedList]`
- Embedded при dehydrate: сериализует все свойства ReflectionClass (без атрибутов)
## EntityMap (`src/Orm/EntityMap.php`)
Кеширует метаданные entity (reflection). `EntityMap::of(ClassName::class)` возвращает объект с:
- `collectionName` — из `#[Collection]`
- `fields` — список `FieldMetadata` (property, field name, флаги embedded)
- `idField()``FieldMetadata` поля с `#[Id]`