Skip to content

Commit 024097a

Browse files
authored
Merge pull request #4 from Fedott/dev-mongodb
Some implementations for ModelManager
2 parents 119825e + 7eccb1d commit 024097a

14 files changed

+801
-307
lines changed

.idea/async-data-mapper.iml

Lines changed: 14 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/php.xml

Lines changed: 58 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.travis.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,14 @@ matrix:
1111
- php: nightly
1212
fast_finish: true
1313

14+
services:
15+
- mongodb
16+
17+
before_install: echo "extension = mongodb.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
18+
1419
install:
1520
- composer self-update
16-
- composer install --no-interaction --prefer-source
21+
- composer install --no-interaction
1722

1823
script:
1924
- php vendor/bin/phpunit --coverage-text --coverage-clover build/logs/clover.xml

composer.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
{
22
"name": "fedot/async-data-mapper",
33
"description": "Simple async datamaper",
4-
"minimum-stability": "dev",
5-
"prefer-stable": true,
64
"license": "MIT",
75
"authors": [
86
{
@@ -22,17 +20,19 @@
2220
},
2321
"require": {
2422
"php": "^7.1",
25-
"amphp/amp": "^2@dev",
23+
"amphp/amp": "^2",
2624
"jms/metadata": "^1.6",
2725
"doctrine/annotations": "^1.4",
2826
"doctrine/instantiator": "^1.0"
2927
},
3028
"require-dev": {
31-
"amphp/redis": "dev-amp_v2",
32-
"symfony/serializer": "^3.2",
29+
"amphp/redis": "^0.3",
30+
"symfony/serializer": "^3.3",
3331
"phpunit/phpunit": "^6.0",
34-
"symfony/property-access": "^3.2",
35-
"symfony/property-info": "^3.2"
32+
"symfony/property-access": "^3.3",
33+
"symfony/property-info": "^3.3",
34+
"mongodb/mongodb": "^1.1",
35+
"amphp/process": "^0.2.1"
3636
},
3737
"suggest": {
3838
"amphp/redis": "Needed for Redis implementation",
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace Fedot\DataMapper;
4+
5+
use Amp\Promise;
6+
use Doctrine\Instantiator\InstantiatorInterface;
7+
use Fedot\DataMapper\Metadata\ClassMetadata;
8+
use Fedot\DataMapper\Metadata\PropertyMetadata;
9+
use Metadata\MetadataFactory;
10+
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
11+
use function Amp\call;
12+
use function Amp\Promise\all;
13+
14+
abstract class AbstractModelManager implements ModelManagerInterface
15+
{
16+
abstract protected function upsertModel(ClassMetadata $classMetadata, $model): Promise;
17+
18+
abstract protected function removeModel(ClassMetadata $classMetadata, $model): Promise;
19+
20+
abstract protected function findRawModel(ClassMetadata $classMetadata, string $id): Promise;
21+
22+
abstract protected function getMetadataFactory(): MetadataFactory;
23+
abstract protected function getPropertyAccessor(): PropertyAccessorInterface;
24+
abstract protected function getInstantiator(): InstantiatorInterface;
25+
abstract protected function getMaxDepth(): int;
26+
27+
public function persist($model, IdentityMap $identityMap = null): Promise
28+
{
29+
return call(function ($model, ?IdentityMap $identityMap) {
30+
if (null === $identityMap) {
31+
$identityMap = new IdentityMap();
32+
}
33+
34+
/** @var ClassMetadata $classMetadata */
35+
$classMetadata = $this->getMetadataFactory()->getMetadataForClass(get_class($model));
36+
37+
yield $this->upsertModel($classMetadata, $model);
38+
39+
$identityMap->add($classMetadata, $this->getIdFromModel($classMetadata, $model), $model);
40+
41+
return true;
42+
}, $model, $identityMap);
43+
}
44+
45+
public function remove($model, IdentityMap $identityMap = null): Promise
46+
{
47+
return call(function ($model, ?IdentityMap $identityMap) {
48+
if (null === $identityMap) {
49+
$identityMap = new IdentityMap();
50+
}
51+
52+
/** @var ClassMetadata $classMetadata */
53+
$classMetadata = $this->getMetadataFactory()->getMetadataForClass(get_class($model));
54+
55+
yield $this->removeModel($classMetadata, $model);
56+
57+
$identityMap->delete($classMetadata, $this->getIdFromModel($classMetadata, $model));
58+
59+
return true;
60+
}, $model, $identityMap);
61+
}
62+
63+
public function find(string $class, string $id, int $depthLevel = 1, IdentityMap $identityMap = null): Promise
64+
{
65+
return call(function (string $class, string $id, int $depthLevel = 1, ?IdentityMap $identityMap) {
66+
if (null === $identityMap) {
67+
$identityMap = new IdentityMap();
68+
}
69+
70+
/** @var ClassMetadata $classMetadata */
71+
$classMetadata = $this->getMetadataFactory()->getMetadataForClass($class);
72+
73+
if ($identityMap->has($classMetadata, $id)) {
74+
$modelInstance = $identityMap->get($classMetadata, $id);
75+
} else {
76+
$modelInstance = $this->getInstantiator()->instantiate($class);
77+
78+
$identityMap->add($classMetadata, $id, $modelInstance);
79+
80+
$modelData = yield $this->findRawModel($classMetadata, $id);
81+
82+
if (empty($modelData)) {
83+
$modelInstance = null;
84+
} else {
85+
/** @var PropertyMetadata $propertyMetadata */
86+
foreach ($classMetadata->propertyMetadata as $propertyMetadata) {
87+
if (array_key_exists($propertyMetadata->name, $modelData)) {
88+
if ($propertyMetadata->isField) {
89+
$propertyMetadata->setValue($modelInstance, $modelData[$propertyMetadata->name]);
90+
} elseif ($depthLevel <= $this->getMaxDepth() && !empty($modelData[$propertyMetadata->name])) {
91+
if ($propertyMetadata->referenceType === 'one') {
92+
$referenceModel = yield $this->find(
93+
$propertyMetadata->referenceTarget,
94+
$modelData[$propertyMetadata->name],
95+
$depthLevel + 1,
96+
$identityMap
97+
);
98+
$propertyMetadata->setValue($modelInstance, $referenceModel);
99+
} elseif ($propertyMetadata->referenceType === 'many') {
100+
$referenceModels = [];
101+
foreach (explode(',', $modelData[$propertyMetadata->name]) as $referenceId) {
102+
$referenceModels[] = $this->find(
103+
$propertyMetadata->referenceTarget,
104+
$referenceId,
105+
$depthLevel + 1,
106+
$identityMap
107+
);
108+
}
109+
110+
if (count($referenceModels) > 0) {
111+
$referenceModels = yield all($referenceModels);
112+
ksort($referenceModels);
113+
}
114+
115+
$propertyMetadata->setValue($modelInstance, $referenceModels);
116+
}
117+
}
118+
} elseif (
119+
!array_key_exists($propertyMetadata->name, $modelData)
120+
&& $propertyMetadata->referenceType === 'many'
121+
) {
122+
$propertyMetadata->setValue($modelInstance, []);
123+
}
124+
}
125+
}
126+
}
127+
128+
return $modelInstance;
129+
}, $class, $id, $depthLevel, $identityMap);
130+
}
131+
132+
protected function getModelData(ClassMetadata $classMetadata, $model): array
133+
{
134+
$data = [];
135+
136+
/** @var PropertyMetadata $propertyMetadata */
137+
foreach ($classMetadata->propertyMetadata as $propertyMetadata) {
138+
if ($propertyMetadata->isField) {
139+
$data[$propertyMetadata->name] = $this->getPropertyAccessor()->getValue($model, $propertyMetadata->name);
140+
} elseif ($propertyMetadata->referenceType === 'one') {
141+
/** @var ClassMetadata $referenceClassMetadata */
142+
$referenceClassMetadata = $this->getMetadataFactory()->getMetadataForClass(
143+
$propertyMetadata->referenceTarget
144+
);
145+
146+
$referenceModel = $this->getPropertyAccessor()->getValue($model, $propertyMetadata->name);
147+
if (null !== $referenceModel) {
148+
$referenceId = $this->getPropertyAccessor()->getValue($referenceModel, $referenceClassMetadata->idField);
149+
$data[$propertyMetadata->name] = $referenceId;
150+
}
151+
} elseif ($propertyMetadata->referenceType === 'many') {
152+
/** @var ClassMetadata $referenceClassMetadata */
153+
$referenceClassMetadata = $this->getMetadataFactory()->getMetadataForClass(
154+
$propertyMetadata->referenceTarget
155+
);
156+
157+
$referenceModels = $this->getPropertyAccessor()->getValue($model, $propertyMetadata->name);
158+
159+
$referenceIds = [];
160+
foreach ($referenceModels as $referenceModel) {
161+
$referenceIds[] = $this->getPropertyAccessor()
162+
->getValue($referenceModel, $referenceClassMetadata->idField);
163+
}
164+
165+
if (count($referenceIds) > 0) {
166+
$data[$propertyMetadata->name] = implode(',', $referenceIds);
167+
}
168+
}
169+
}
170+
171+
return $data;
172+
}
173+
174+
protected function getIdFromModel(ClassMetadata $classMetadata, $model): string
175+
{
176+
return $this->getPropertyAccessor()->getValue($model, $classMetadata->idField);
177+
}
178+
}

0 commit comments

Comments
 (0)