Skip to content

Commit 3390428

Browse files
committed
change api
1 parent 939ffad commit 3390428

8 files changed

Lines changed: 240 additions & 101 deletions

File tree

README.md

Lines changed: 2 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -86,73 +86,6 @@ $manager = RangoRepositoryManager::create(
8686

8787
$repository = $manager->get(Profile::class);
8888

89-
$repository->save(new Profile('r-1', 'Rango', Status::ACTIVE, [new Skill('php')]));
90-
91-
$profile = $repository->load('r-1');
92-
```
93-
94-
## ✨ Supported Features
95-
96-
### Document Mapping
97-
98-
| Attribute | Purpose |
99-
| ------------- | --------------------------------------------- |
100-
| `#[Document]` | Defines the collection name |
101-
| `#[Id]` | Marks the identifier property mapped to `_id` |
102-
| `#[Index]` | Defines database indexes |
103-
104-
Example:
105-
106-
```php
107-
#[Document('users')]
108-
#[Index('by_email', ['email' => 'asc'], unique: true)]
109-
class User
110-
{
111-
#[Id]
112-
public string $id;
113-
}
114-
```
115-
116-
---
117-
118-
### Repository API
119-
120-
| Operation | Method |
121-
| ---------- | ----------------- |
122-
| **Save** | `save($document)` |
123-
| **Load** | `load($id)` |
124-
| **Find** | `find($criteria)` |
125-
| **Exists** | `has($id)` |
126-
| **Count** | `count()` |
127-
| **Delete** | `remove($id)` |
128-
129-
Example:
130-
131-
```php
132-
$repository->save($document);
133-
134-
$user = $repository->load('user-1');
135-
136-
$activeUsers = $repository->find([
137-
'status' => 'active'
138-
]);
139-
```
140-
141-
---
142-
143-
### Index Management
144-
145-
Repositories also provide helpers to manage database indexes.
146-
147-
| Method | Description |
148-
| ---------------------------------- | ------------------------------------------- |
149-
| `createCollection()` | Creates the collection if it does not exist |
150-
| `updateIndexes()` | Creates or updates defined indexes |
151-
| `updateIndexes(dropUnknown: true)` | Drops indexes not defined in metadata |
152-
153-
Example:
154-
155-
```php
156-
$repository->createCollection();
157-
$repository->updateIndexes();
89+
$repository->persist(new Profile('r-1', 'Rango', Status::ACTIVE, [new Skill('php')]));
90+
$profile = $repository->find('r-1');
15891
```

src/Hydrator/RangoCipherKeyStore.php

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,7 @@ public function remove(string $id): void
5959
$this->collection()->deleteOne(['_id' => $id]);
6060
}
6161

62-
/**
63-
* @return Collection<CipherKeyData>
64-
*/
62+
/** @return Collection<CipherKeyData> */
6563
private function collection(): Collection
6664
{
6765
return $this->database->selectCollection($this->collection);
@@ -83,10 +81,7 @@ public function removeWithSubjectId(string $subjectId): void
8381
$this->collection()->deleteMany(['subject_id' => $subjectId]);
8482
}
8583

86-
/**
87-
* @param CipherKeyData $data
88-
* @return CipherKey
89-
*/
84+
/** @param CipherKeyData $data */
9085
private function hydrate(array $data): CipherKey
9186
{
9287
return new CipherKey(

src/Repository/RangoRepository.php

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,26 @@ public function __construct(
2828
}
2929

3030
/** @param T $object */
31-
public function save(object $object): void
31+
public function persist(object $object): void
3232
{
33+
if ($object::class !== $this->metadata->className) {
34+
throw new WrongClass($this->metadata->className, $object::class);
35+
}
36+
3337
$data = $this->hydrator->extract($object);
3438

3539
$this->collection()->insertOne($data);
3640
}
3741

38-
/** @return T */
39-
public function load(string $id): object
42+
/** @return T|null */
43+
public function find(string $id): object|null
4044
{
4145
$data = $this->collection()->findOne(['_id' => $id]);
4246

47+
if ($data === null) {
48+
return null;
49+
}
50+
4351
return $this->hydrator->hydrate($this->metadata->className, $data);
4452
}
4553

@@ -48,20 +56,57 @@ public function remove(string $id): void
4856
$this->collection()->deleteOne(['_id' => $id]);
4957
}
5058

51-
/**
52-
* @param array<string, mixed> $filter
53-
*
54-
* @return iterable<T>
55-
*/
56-
public function find(array $filter = []): iterable
59+
public function findAll(): iterable
5760
{
58-
$cursor = $this->collection()->find($filter);
61+
$cursor = $this->collection()->find();
5962

6063
foreach ($cursor as $document) {
6164
yield $this->hydrator->hydrate($this->metadata->className, $document);
6265
}
6366
}
6467

68+
public function findBy(array $filter, array|null $orderBy = null, int|null $limit = null, int|null $offset = null): iterable
69+
{
70+
$options = [];
71+
72+
if ($limit !== null) {
73+
$options['limit'] = $limit;
74+
}
75+
76+
if ($offset !== null) {
77+
$options['skip'] = $offset;
78+
}
79+
80+
if ($orderBy !== null) {
81+
$options['sort'] = array_map(
82+
static fn ($direction) => $direction === 'desc' ? -1 : 1,
83+
$orderBy,
84+
);
85+
}
86+
87+
$cursor = $this->collection()->find($filter, $options);
88+
89+
foreach ($cursor as $document) {
90+
yield $this->hydrator->hydrate($this->metadata->className, $document);
91+
}
92+
}
93+
94+
public function findOneBy(array $filter = [], array|null $orderBy = null): object|null
95+
{
96+
$options = ['limit' => 1];
97+
98+
if ($orderBy !== null) {
99+
$options['sort'] = array_map(
100+
static fn ($direction) => $direction === 'desc' ? -1 : 1,
101+
$orderBy,
102+
);
103+
}
104+
105+
$data = $this->collection()->findOne($filter, $options);
106+
107+
return $data ? $this->hydrator->hydrate($this->metadata->className, $data) : null;
108+
}
109+
65110
public function count(): int
66111
{
67112
return $this->collection()->countDocuments();
@@ -77,9 +122,7 @@ public function database(): Database
77122
return $this->database;
78123
}
79124

80-
/**
81-
* @return Collection<array<string, mixed>>
82-
*/
125+
/** @return Collection<array<string, mixed>> */
83126
public function collection(): Collection
84127
{
85128
return $this->database->getCollection($this->metadata->collection);

src/Repository/RangoRepositoryManager.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,7 @@ public function get(string $documentClass): RangoRepository
4747
return $this->repositories[$documentClass];
4848
}
4949

50-
/**
51-
* @param list<Extension> $extensions
52-
*/
50+
/** @param list<Extension> $extensions */
5351
public function create(Database $database, array $extensions = []): self
5452
{
5553
$metadataFactory = new AttributeDocumentMetadataFactory();

src/Repository/Repository.php

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,36 @@
88
interface Repository
99
{
1010
/** @param T $object */
11-
public function save(object $object): void;
11+
public function persist(object $object): void;
1212

13-
/** @return T */
14-
public function load(string $id): object;
13+
/** @return T|null */
14+
public function find(string $id): object|null;
1515

1616
public function remove(string $id): void;
1717

18+
/** @return iterable<T> */
19+
public function findAll(): iterable;
20+
1821
/**
19-
* @param array<string, mixed> $filter
22+
* @param array<string, mixed> $filter
23+
* @param array<string, 'asc'|'desc'>|null $orderBy
2024
*
2125
* @return iterable<T>
2226
*/
23-
public function find(array $filter = []): iterable;
27+
public function findBy(
28+
array $filter,
29+
array|null $orderBy = null,
30+
int|null $limit = null,
31+
int|null $offset = null,
32+
): iterable;
33+
34+
/**
35+
* @param array<string, mixed> $filter
36+
* @param array<string, 'asc'|'desc'>|null $orderBy
37+
*
38+
* @return T|null
39+
*/
40+
public function findOneBy(array $filter = [], array|null $orderBy = null): object|null;
2441

2542
public function count(): int;
2643

src/Repository/WrongClass.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Patchlevel\ODM\Repository;
6+
7+
use RuntimeException;
8+
9+
use function sprintf;
10+
11+
class WrongClass extends RuntimeException
12+
{
13+
public function __construct(string $expected, string $given)
14+
{
15+
parent::__construct(sprintf('Expected class "%s", got "%s".', $expected, $given));
16+
}
17+
}

tests/Integration/Fixtures/SkillNormalizer.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
use Patchlevel\Hydrator\Normalizer\InvalidType;
99
use Patchlevel\Hydrator\Normalizer\NormalizerWithContext;
1010

11+
use function is_string;
12+
1113
#[Attribute(Attribute::TARGET_CLASS)]
1214
final class SkillNormalizer implements NormalizerWithContext
1315
{

0 commit comments

Comments
 (0)