8000 #37180 don't pass collection query parameter to driver, dsn should ta… · symfony/symfony@599c128 · GitHub
[go: up one dir, main page]

Skip to content

Commit 599c128

Browse files
author
Joe Bennett
committed
#37180 don't pass collection query parameter to driver, dsn should take precedence over options
1 parent 8bb0897 commit 599c128

File tree

2 files changed

+75
-24
lines changed

2 files changed

+75
-24
lines changed

src/Symfony/Component/Lock/Store/MongoDbStore.php

Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ class MongoDbStore implements BlockingStoreInterface
7272
* driverOptions: Array of driver options. [used when $mongo is a URI]
7373
*
7474
* When using a URI string:
75-
* the database is determined from the "database" option, otherwise the uri's path is used.
76-
* the collection is determined from the "collection" option, otherwise the uri's "collection" querystring parameter is used.
75+
* The database is determined from the uri's path, otherwise the "database" option is used. To specify an alternate authentication database; "authSource" uriOption or querystring parameter must be used.
76+
* The collection is determined from the uri's "collection" querystring parameter, otherwise the "collection" option is used.
7777
*
7878
* For example: mongodb://myuser:mypass@myhost/mydatabase?collection=mycollection
7979
*
@@ -104,34 +104,20 @@ public function __construct($mongo, array $options = [], float $initialTtl = 300
104104
if ($mongo instanceof Collection) {
105105
$this->collection = $mongo;
106106
} elseif ($mongo instanceof Client) {
107-
if (null === $this->options['database']) {
108-
throw new InvalidArgumentException(sprintf('"%s()" requires the "database" option when constructing with a "%s".', __METHOD__, Client::class));
109-
}
110-
if (null === $this->options['collection']) {
111-
throw new InvalidArgumentException(sprintf('"%s()" requires the "collection" option when constructing with a "%s".', __METHOD__, Client::class));
112-
}
113-
114107
$this->client = $mongo;
115108
} elseif (\is_string($mongo)) {
116-
if (false === $parsedUrl = parse_url($mongo)) {
117-
throw new InvalidArgumentException(sprintf('The given MongoDB Connection URI "%s" is invalid.', $mongo));
118-
}
119-
$query = [];
120-
if (isset($parsedUrl['query'])) {
121-
parse_str($parsedUrl['query'], $query);
122-
}
123-
$this->options['collection'] = $this->options['collection'] ?? $query['collection'] ?? null;
124-
$this->options['database'] = $this->options['database'] ?? ltrim($parsedUrl['path'] ?? '', '/') ?: null;
109+
$this->uri = $this->skimUri($mongo);
110+
} else {
111+
throw new InvalidArgumentException(sprintf('"%s()" requires "%s" or "%s" or URI as first argument, "%s" given.', __METHOD__, Collection::class, Client::class, get_debug_type($mongo)));
112+
}
113+
114+
if (!($mongo instanceof Collection)) {
125115
if (null === 10000 $this->options['database']) {
126-
throw new InvalidArgumentException(sprintf('"%s()" requires the "database" in the URI path or option when constructing with a URI.', __METHOD__));
116+
throw new InvalidArgumentException(sprintf('"%s()" requires the "database" in the URI path or option.', __METHOD__));
127117
}
128118
if (null === $this->options['collection']) {
129-
throw new InvalidArgumentException(sprintf('"%s()" requires the "collection" in the URI querystring or option when constructing with a URI.', __METHOD__));
119+
throw new InvalidArgumentException(sprintf('"%s()" requires the "collection" in the URI querystring or option.', __METHOD__));
130120
}
131-
132-
$this->uri = $mongo;
133-
} else {
134-
throw new InvalidArgumentException(sprintf('"%s()" requires "%s" or "%s" or URI as first argument, "%s" given.', __METHOD__, Collection::class, Client::class, get_debug_type($mongo)));
135121
}
136122

137123
if ($this->options['gcProbablity'] < 0.0 || $this->options['gcProbablity'] > 1.0) {
@@ -143,6 +129,41 @@ public function __construct($mongo, array $options = [], float $initialTtl = 300
143129
}
144130
}
145131

132+
/**
133+
* Extract default database and collection from given connection uri and remove collection querystring.
134+
*/
135+
private function skimUri(string $uri): string
136+
{
137+
if (false === $parsedUrl = parse_url($uri)) {
138+
throw new InvalidArgumentException(sprintf('The given MongoDB Connection URI "%s" is invalid.', $mongo));
139+
}
140+
141+
$query = [];
142+
if (isset($parsedUrl['query'])) {
143+
parse_str($parsedUrl['query'], $query);
144+
}
145+
146+
if (isset($query['collection'])) {
147+
$this->options['collection'] = $query['collection'];
148+
$queryStringPos = strrpos($uri, $parsedUrl['query']);
149+
unset($query['collection']);
150+
$prefix = substr($uri, 0, $queryStringPos);
151+
$newQuery = http_build_query($query, '', '&', PHP_QUERY_RFC3986);
152+
if (empty($newQuery)) {
153+
$prefix = rtrim($prefix, '?');
154+
}
155+
$suffix = substr($uri, $queryStringPos + \strlen($parsedUrl['query']));
156+
$uri = $prefix.$newQuery.$suffix;
157+
}
158+
159+
$pathDb = ltrim($parsedUrl['path'] ?? '', '/') ?: null;
160+
if (null !== $pathDb) {
161+
$this->options['database'] = $pathDb;
162+
}
163+
164+
return $uri;
165+
}
166+
146167
/**
147168
* Creates a TTL index to automatically remove expired locks.
148169
*

src/Symfony/Component/Lock/Tests/Store/MongoDbStoreTest.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,4 +141,34 @@ public function provideInvalidConstructorArgs()
141141
yield ['mongodb://localhost/test', []];
142142
yield ['mongodb://localhost/', []];
143143
}
144+
145+
public function testCollectionDsnPrecedence()
146+
{
147+
$client = self::getMongoClient();
148+
149+
$store = new MongoDbStore('mongodb://localhost/test?collection=lock_dsn', ['collection' => 'lock_option']);
150+
$storeReflection = new \ReflectionObject($store);
151+
152+
$uriProperty = $storeReflection->getProperty('uri');
153+
$uriProperty->setAccessible(true);
154+
$uri = $uriProperty->getValue($store);
155+
$this->assertSame('mongodb://localhost/test', $uri);
156+
157+
$optionsProperty = $storeReflection->getProperty('options');
158+
$optionsProperty->setAccessible(true);
159+
$options = $optionsProperty->getValue($store);
160+
$this->assertSame('lock_dsn', $options['collection']);
161+
}
162+
163+
public function testDatabaseDsnPrecedence()
164+
{
165+
$client = self::getMongoClient();
166+
167+
$store = new MongoDbStore('mongodb://localhost/test_dsn?collection=lock', ['database' => 'test_option']);
168+
$storeReflection = new \ReflectionObject($store);
169+
$optionsProperty = $storeReflection->getProperty('options');
170+
$optionsProperty->setAccessible(true);
171+
$options = $optionsProperty->getValue($store);
172+
$this->assertSame('test_dsn', $options['database']);
173+
}
144174
}

0 commit comments

Comments
 (0)
0