Add knowledge base

This commit is contained in:
2026-04-06 15:43:45 +03:00
parent df1d2a58bf
commit ab89913ebf
11 changed files with 514 additions and 112 deletions

80
.claude/kb/orm.md Normal file
View File

@@ -0,0 +1,80 @@
# 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]`