Skip to content

Commit b1d6b9f

Browse files
committed
OptionsResolver, refactoring
1 parent 33b3dc0 commit b1d6b9f

26 files changed

+287
-265
lines changed

src/Collection.php

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
use Tequila\MongoDB\Command\DropCollection;
1212
use Tequila\MongoDB\Command\DropIndexes;
1313
use Tequila\MongoDB\Command\ListIndexes;
14-
use Tequila\MongoDB\Exception\InvalidArgumentException;
1514
use Tequila\MongoDB\Operation\Find;
1615
use Tequila\MongoDB\Options\DatabaseAndCollectionOptions;
1716
use Tequila\MongoDB\Options\Driver\TypeMapOptions;
@@ -95,25 +94,13 @@ public function aggregate(array $pipeline, array $options = [])
9594
$defaults = [
9695
'readConcern' => $this->readConcern,
9796
'readPreference' => $this->readPreference,
97+
'typeMap' => $this->typeMap,
9898
];
9999

100-
if (isset($options['typeMap'])) {
101-
if (!is_array($options['typeMap'])) {
102-
throw new InvalidArgumentException('Option "typeMap" must be an array');
103-
}
104-
105-
$typeMap = TypeMapOptions::resolve($options['typeMap']);
106-
unset($options['typeMap']);
107-
}
108-
109100
$options += $defaults;
110101
$command = new Aggregate($this->databaseName, $this->collectionName, $pipeline, $options);
111102
$cursor = $command->execute($this->manager);
112103

113-
if (isset($typeMap)) {
114-
$cursor->setTypeMap($typeMap);
115-
}
116-
117104
return $cursor;
118105
}
119106

@@ -230,7 +217,7 @@ public function find($filter = [], array $options = [])
230217
'readConcern' => $this->readConcern,
231218
'typeMap' => $this->typeMap,
232219
];
233-
$options = $options + $defaults;
220+
$options += $defaults;
234221
$operation = new Find($filter, $options);
235222

236223
return $operation->execute($this->manager, $this->databaseName, $this->collectionName);

src/Command/Aggregate.php

Lines changed: 122 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@
66
use MongoDB\Driver\Manager;
77
use MongoDB\Driver\ReadConcern;
88
use MongoDB\Driver\ReadPreference;
9-
use Tequila\MongoDB\Command\Options\AggregateOptions;
9+
use Symfony\Component\OptionsResolver\Options;
10+
use Tequila\MongoDB\Exception\InvalidArgumentException;
11+
use Tequila\MongoDB\Exception\UnexpectedResultException;
12+
use Tequila\MongoDB\Options\Driver\DriverOptions;
13+
use Tequila\MongoDB\Options\Driver\TypeMapOptions;
14+
use Tequila\MongoDB\Options\OptionsResolver;
1015

1116
class Aggregate implements CommandInterface
1217
{
@@ -30,6 +35,21 @@ class Aggregate implements CommandInterface
3035
*/
3136
private $options;
3237

38+
/**
39+
* @var ReadPreference|null
40+
*/
41+
private $readPreference;
42+
43+
/**
44+
* @var array
45+
*/
46+
private $typeMap;
47+
48+
/**
49+
* @var bool
50+
*/
51+
private $useCursor;
52+
3353
/**
3454
* @param string $databaseName
3555
* @param string $collectionName
@@ -41,38 +61,118 @@ public function __construct($databaseName, $collectionName, array $pipeline, arr
4161
$this->databaseName = (string)$databaseName;
4262
$this->collectionName = (string)$collectionName;
4363
$this->pipeline = $pipeline;
44-
$this->options = AggregateOptions::resolve($options);
64+
$this->options = $this->resolve($options);
4565
}
4666

4767
public function execute(Manager $manager)
4868
{
49-
if (isset($this->options['readConcern'])) {
50-
/** @var ReadConcern $readConcern */
51-
$readConcern = $this->options['readConcern'];
52-
if ($this->hasOutStage() && ReadConcern::MAJORITY === $readConcern->getLevel()) {
53-
unset($this->options['readConcern']);
54-
} else {
55-
$this->options['readConcern'] = ['level' => $readConcern->getLevel()];
56-
}
69+
$options = ['aggregate' => $this->collectionName, 'pipeline' => $this->pipeline];
70+
$options += $this->options;
71+
$command = new Command($options);
72+
73+
$cursor = $manager->executeCommand($this->databaseName, $command, $this->readPreference);
74+
if ($this->useCursor) {
75+
$cursor->setTypeMap($this->typeMap);
76+
77+
return $cursor;
78+
}
79+
80+
$cursor->setTypeMap(TypeMapOptions::getArrayTypeMap());
81+
$resultDocument = current($cursor->toArray());
82+
if (!isset($resultDocument['result']) || !is_array($resultDocument['result'])) {
83+
throw new UnexpectedResultException(
84+
'Command "aggregate" did not return expected "result" array'
85+
);
5786
}
5887

59-
if ($this->hasOutStage()) {
60-
$readPreference = new ReadPreference(ReadPreference::RP_PRIMARY);
61-
} else {
62-
if (isset($this->options['readPreference'])) {
63-
$readPreference = $this->options['readPreference'];
88+
return $resultDocument['result'];
89+
}
90+
91+
/**
92+
* @param array $options
93+
* @return array
94+
*/
95+
private function resolve(array $options)
96+
{
97+
$resolver = new OptionsResolver();
98+
$this->configureOptions($resolver);
99+
$options = $resolver->resolve($options);
100+
101+
$this->readPreference = isset($this->options['readPreference']) ? $this->options['readPreference'] : null;
102+
unset($options['readPreference']);
103+
104+
$this->typeMap = $options['typeMap'];
105+
unset($options['typeMap']);
106+
107+
$this->useCursor = $options['useCursor'];
108+
unset($options['useCursor']);
109+
110+
if ($this->useCursor) {
111+
if (isset($options['batchSize'])) {
112+
$options['cursor'] = ['batchSize' => $options['batchSize']];
113+
unset ($options['batchSize']);
64114
} else {
65-
$readPreference = null;
115+
$options['cursor'] = new \stdClass();
66116
}
67117
}
68118

69-
unset($this->options['readPreference']);
119+
return $options;
120+
}
70121

71-
$options = ['aggregate' => $this->collectionName, 'pipeline' => $this->pipeline];
72-
$options += $this->options;
73-
$command = new Command($options);
122+
private function configureOptions(OptionsResolver $resolver)
123+
{
124+
DriverOptions::configureOptions($resolver);
125+
126+
$resolver->setDefined([
127+
'allowDiskUse',
128+
'batchSize',
129+
'bypassDocumentValidation',
130+
'maxTimeMS',
131+
'readConcern',
132+
'readPreference',
133+
'useCursor',
134+
]);
135+
136+
$resolver
137+
->setAllowedTypes('allowDiskUse', 'bool')
138+
->setAllowedTypes('batchSize', 'integer')
139+
->setAllowedTypes('bypassDocumentValidation', 'bool')
140+
->setAllowedTypes('maxTimeMS', 'integer')
141+
->setAllowedTypes('readConcern', ReadConcern::class)
142+
->setAllowedTypes('readPreference', ReadPreference::class)
143+
->setAllowedTypes('useCursor', 'bool');
144+
145+
$resolver->setDefault('useCursor', true);
74146

75-
return $manager->executeCommand($this->databaseName, $command, $readPreference);
147+
$resolver->setNormalizer('batchSize', function(Options $options, $batchSize) {
148+
if (!isset($options['useCursor']) || false === $options['useCursor']) {
149+
throw new InvalidArgumentException(
150+
'Option "batchSize" is meaningless unless option "useCursor" is set to true'
151+
);
152+
}
153+
154+
return $batchSize;
155+
});
156+
157+
$resolver->setNormalizer('readConcern', function(Options $options, ReadConcern $readConcern) {
158+
if (null === $readConcern->getLevel() ) {
159+
return null;
160+
}
161+
162+
if ($this->hasOutStage() && ReadConcern::MAJORITY === $readConcern->getLevel()) {
163+
return null;
164+
}
165+
166+
return ['level' => $readConcern->getLevel()];
167+
});
168+
169+
$resolver->setNormalizer('readPreference', function(Options $options, ReadPreference $readPreference) {
170+
if ($this->hasOutStage()) {
171+
return new ReadPreference(ReadPreference::RP_PRIMARY);
172+
}
173+
174+
return $readPreference;
175+
});
76176
}
77177

78178
private function hasOutStage()
@@ -81,4 +181,5 @@ private function hasOutStage()
81181

82182
return '$out' === key($lastStage);
83183
}
184+
84185
}

src/Command/Options/AggregateOptions.php

Lines changed: 0 additions & 70 deletions
This file was deleted.

src/Command/Options/CreateCollectionOptions.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
namespace Tequila\MongoDB\Command\Options;
44

55
use Symfony\Component\OptionsResolver\Options;
6-
use Symfony\Component\OptionsResolver\OptionsResolver;
76
use Tequila\MongoDB\Exception\InvalidArgumentException;
87
use Tequila\MongoDB\Options\OptionsInterface;
8+
use Tequila\MongoDB\Options\OptionsResolver;
99
use Tequila\MongoDB\Options\Traits\CachedResolverTrait;
1010

1111
class CreateCollectionOptions implements OptionsInterface

src/Command/Options/ListCollectionsOptions.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
namespace Tequila\MongoDB\Command\Options;
44

55
use Symfony\Component\OptionsResolver\Options;
6-
use Symfony\Component\OptionsResolver\OptionsResolver;
76
use Tequila\MongoDB\Options\OptionsInterface;
7+
use Tequila\MongoDB\Options\OptionsResolver;
88
use Tequila\MongoDB\Options\Traits\CachedResolverTrait;
99

1010
class ListCollectionsOptions implements OptionsInterface

0 commit comments

Comments
 (0)