Revert MongoDB support to 1.x
This commit is contained in:
parent
6252dd6107
commit
a575479206
40
.gitignore
vendored
40
.gitignore
vendored
|
|
@ -1,52 +1,14 @@
|
|||
# ---> Composer
|
||||
composer.phar
|
||||
/vendor/
|
||||
|
||||
# Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control
|
||||
# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
|
||||
# composer.lock
|
||||
|
||||
# ---> JetBrains
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
.idea/
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/artifacts
|
||||
# .idea/compiler.xml
|
||||
# .idea/jarRepositories.xml
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
# *.iml
|
||||
# *.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
.junie/
|
||||
.phpunit.result.cache
|
||||
|
|
@ -1 +0,0 @@
|
|||
{"version":2,"defects":{"Pairity\\Tests\\BelongsToManyMysqlTest::testBelongsToManyEagerAndHelpers":1,"Pairity\\Tests\\BelongsToManySqliteTest::testBelongsToManyEagerAndPivotHelpers":7,"Pairity\\Tests\\CastersAndAccessorsSqliteTest::testCustomCasterAndDtoAccessorsMutators":7,"Pairity\\Tests\\JoinEagerMysqlTest::testJoinEagerHasManyAndBelongsTo":1,"Pairity\\Tests\\JoinEagerSqliteTest::testHasManyJoinEagerWithProjectionAndSoftDeleteScope":7,"Pairity\\Tests\\JoinEagerSqliteTest::testBelongsToJoinEagerSingleLevel":8,"Pairity\\Tests\\MongoAdapterTest::testCrudCycle":1,"Pairity\\Tests\\MongoDaoTest::testCrudViaDao":8,"Pairity\\Tests\\MongoOptimisticLockTest::testVersionIncrementOnUpdate":8,"Pairity\\Tests\\MongoPaginationTest::testPaginateAndSimplePaginateWithScopes":8,"Pairity\\Tests\\MongoRelationsTest::testEagerAndLazyRelations":8,"Pairity\\Tests\\MysqlSmokeTest::testCreateAndDropTable":1,"Pairity\\Tests\\PaginationSqliteTest::testPaginateAndSimplePaginateWithScopesAndRelations":7,"Pairity\\Tests\\RelationsNestedConstraintsSqliteTest::testNestedEagerAndPerRelationFieldsConstraint":7,"Pairity\\Tests\\SchemaBuilderSqliteTest::testCreateAlterDropCycle":8,"Pairity\\Tests\\UnitOfWorkCascadeMongoTest::testDeleteByIdCascadesToChildren":8,"Pairity\\Tests\\UnitOfWorkCascadeSqliteTest::testDeleteByIdCascadesToChildren":7,"Pairity\\Tests\\UnitOfWorkMongoTest::testDeferredUpdateAndDeleteCommit":8,"Pairity\\Tests\\UnitOfWorkMongoTest::testRollbackOnExceptionClearsOps":8,"Pairity\\Tests\\MongoEventSystemTest::testDaoEventsFireOnCrud":8,"Pairity\\Tests\\PostgresSmokeTest::testCreateAlterDropCycle":1},"times":{"Pairity\\Tests\\BelongsToManyMysqlTest::testBelongsToManyEagerAndHelpers":0.001,"Pairity\\Tests\\BelongsToManySqliteTest::testBelongsToManyEagerAndPivotHelpers":0.004,"Pairity\\Tests\\CastersAndAccessorsSqliteTest::testCustomCasterAndDtoAccessorsMutators":0,"Pairity\\Tests\\JoinEagerMysqlTest::testJoinEagerHasManyAndBelongsTo":0,"Pairity\\Tests\\JoinEagerSqliteTest::testHasManyJoinEagerWithProjectionAndSoftDeleteScope":0,"Pairity\\Tests\\JoinEagerSqliteTest::testBelongsToJoinEagerSingleLevel":0,"Pairity\\Tests\\MongoAdapterTest::testCrudCycle":0.002,"Pairity\\Tests\\MongoDaoTest::testCrudViaDao":0.001,"Pairity\\Tests\\MongoOptimisticLockTest::testVersionIncrementOnUpdate":0,"Pairity\\Tests\\MongoPaginationTest::testPaginateAndSimplePaginateWithScopes":0,"Pairity\\Tests\\MongoRelationsTest::testEagerAndLazyRelations":0,"Pairity\\Tests\\MysqlSmokeTest::testCreateAndDropTable":0,"Pairity\\Tests\\OptimisticLockSqliteTest::testVersionLockingIncrementsAndBlocksBulkUpdate":0,"Pairity\\Tests\\PaginationSqliteTest::testPaginateAndSimplePaginateWithScopesAndRelations":0.001,"Pairity\\Tests\\RelationsNestedConstraintsSqliteTest::testNestedEagerAndPerRelationFieldsConstraint":0,"Pairity\\Tests\\SchemaBuilderSqliteTest::testCreateAlterDropCycle":0.001,"Pairity\\Tests\\SoftDeletesTimestampsSqliteTest::testTimestampsAndSoftDeletesFlow":0,"Pairity\\Tests\\UnitOfWorkCascadeMongoTest::testDeleteByIdCascadesToChildren":0,"Pairity\\Tests\\UnitOfWorkCascadeSqliteTest::testDeleteByIdCascadesToChildren":0,"Pairity\\Tests\\UnitOfWorkMongoTest::testDeferredUpdateAndDeleteCommit":0,"Pairity\\Tests\\UnitOfWorkMongoTest::testRollbackOnExceptionClearsOps":0,"Pairity\\Tests\\UnitOfWorkSqliteTest::testDeferredUpdateAndDeleteCommit":0,"Pairity\\Tests\\UnitOfWorkSqliteTest::testRollbackOnExceptionClearsOps":0,"Pairity\\Tests\\EventSystemSqliteTest::testDaoEventsForInsertUpdateDeleteAndFind":0,"Pairity\\Tests\\EventSystemSqliteTest::testUowBeforeAfterCommitEvents":0,"Pairity\\Tests\\MongoEventSystemTest::testDaoEventsFireOnCrud":0,"Pairity\\Tests\\PostgresSmokeTest::testCreateAlterDropCycle":0}}
|
||||
|
|
@ -2,6 +2,13 @@
|
|||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
#### [0.1.1] - 2026-01-07
|
||||
|
||||
##### Changed
|
||||
- **MongoDB Downgrade**: Stepped back MongoDB support from `mongodb/mongodb` ^2.0 to ^1.20 for broader compatibility with older `ext-mongodb` environments.
|
||||
- **Refactoring**: Simplified `normalizeFilter` in `MongoClientConnection` for better maintainability.
|
||||
- **Features**: Added `count()` method to `MongoConnectionInterface` and implementations.
|
||||
|
||||
#### [0.1.0] - 2026-01-06
|
||||
|
||||
##### Added
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ composer install
|
|||
vendor/bin/phpunit
|
||||
```
|
||||
|
||||
- **Run MongoDB integration tests** (requires `ext-mongodb >= 2.1` and a reachable server):
|
||||
- **Run MongoDB integration tests** (requires `ext-mongodb >= 1.20` and a reachable server):
|
||||
```bash
|
||||
MONGO_HOST=127.0.0.1 MONGO_PORT=27017 vendor/bin/phpunit --group mongo-integration
|
||||
```
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@
|
|||
},
|
||||
"require": {
|
||||
"php": "^8.2",
|
||||
"ext-mongodb": "*",
|
||||
"mongodb/mongodb": "^2.0",
|
||||
"ext-mongodb": "^1.20",
|
||||
"mongodb/mongodb": "^1.20",
|
||||
"psr/simple-cache": "^3.0"
|
||||
},
|
||||
"autoload": {
|
||||
|
|
|
|||
101
composer.lock
generated
101
composer.lock
generated
|
|
@ -4,28 +4,27 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "64942e8c928a3d237f245d668b7c255b",
|
||||
"content-hash": "11f93ad2569b5071bfe47d842a4fa8da",
|
||||
"packages": [
|
||||
{
|
||||
"name": "mongodb/mongodb",
|
||||
"version": "2.1.2",
|
||||
"version": "1.21.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mongodb/mongo-php-library.git",
|
||||
"reference": "0a2472ba9cbb932f7e43a8770aedb2fc30612a67"
|
||||
"reference": "b8f569ec52542d2f1bfca88286f20d14a7f72536"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mongodb/mongo-php-library/zipball/0a2472ba9cbb932f7e43a8770aedb2fc30612a67",
|
||||
"reference": "0a2472ba9cbb932f7e43a8770aedb2fc30612a67",
|
||||
"url": "https://api.github.com/repos/mongodb/mongo-php-library/zipball/b8f569ec52542d2f1bfca88286f20d14a7f72536",
|
||||
"reference": "b8f569ec52542d2f1bfca88286f20d14a7f72536",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer-runtime-api": "^2.0",
|
||||
"ext-mongodb": "^2.1",
|
||||
"ext-mongodb": "^1.21.0",
|
||||
"php": "^8.1",
|
||||
"psr/log": "^1.1.4|^2|^3",
|
||||
"symfony/polyfill-php85": "^1.32"
|
||||
"psr/log": "^1.1.4|^2|^3"
|
||||
},
|
||||
"replace": {
|
||||
"mongodb/builder": "*"
|
||||
|
|
@ -79,9 +78,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/mongodb/mongo-php-library/issues",
|
||||
"source": "https://github.com/mongodb/mongo-php-library/tree/2.1.2"
|
||||
"source": "https://github.com/mongodb/mongo-php-library/tree/1.21.3"
|
||||
},
|
||||
"time": "2025-10-06T12:12:40+00:00"
|
||||
"time": "2025-09-22T12:34:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/log",
|
||||
|
|
@ -183,86 +182,6 @@
|
|||
"source": "https://github.com/php-fig/simple-cache/tree/3.0.0"
|
||||
},
|
||||
"time": "2021-10-29T13:26:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php85",
|
||||
"version": "v1.33.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php85.git",
|
||||
"reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91",
|
||||
"reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"url": "https://github.com/symfony/polyfill",
|
||||
"name": "symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Php85\\": ""
|
||||
},
|
||||
"classmap": [
|
||||
"Resources/stubs"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill backporting some PHP 8.5+ features to lower PHP versions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php85/tree/v1.33.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nicolas-grekas",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-06-23T16:12:55+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
|
|
@ -1943,7 +1862,7 @@
|
|||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": "^8.2",
|
||||
"ext-mongodb": "*"
|
||||
"ext-mongodb": "^1.20"
|
||||
},
|
||||
"platform-dev": {},
|
||||
"plugin-api-version": "2.6.0"
|
||||
|
|
|
|||
|
|
@ -87,6 +87,12 @@ class MongoClientConnection implements MongoConnectionInterface
|
|||
return '';
|
||||
}
|
||||
|
||||
public function count(string $database, string $collection, array $filter = []): int
|
||||
{
|
||||
$coll = $this->client->selectCollection($database, $collection);
|
||||
return $coll->countDocuments($this->normalizeFilter($filter));
|
||||
}
|
||||
|
||||
public function withSession(callable $callback): mixed
|
||||
{
|
||||
/** @var Session $session */
|
||||
|
|
@ -118,52 +124,26 @@ class MongoClientConnection implements MongoConnectionInterface
|
|||
/** @param array<string,mixed> $filter */
|
||||
private function normalizeFilter(array $filter): array
|
||||
{
|
||||
// Recursively walk the filter and convert any _id string(s) that look like 24-hex to ObjectId
|
||||
$walker = function (&$node, $key = null) use (&$walker) {
|
||||
if (is_array($node)) {
|
||||
foreach ($node as $k => &$v) {
|
||||
$walker($v, $k);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if ($key === '_id' && is_string($node) && preg_match('/^[a-f\d]{24}$/i', $node)) {
|
||||
try { $node = new ObjectId($node); } catch (\Throwable) {}
|
||||
}
|
||||
};
|
||||
|
||||
$convertIdContainer = function (&$value) use (&$convertIdContainer) {
|
||||
// Handle structures like ['_id' => ['$in' => ['...','...']]]
|
||||
if (is_string($value) && preg_match('/^[a-f\d]{24}$/i', $value)) {
|
||||
try { $value = new ObjectId($value); } catch (\Throwable) {}
|
||||
return;
|
||||
}
|
||||
$normalize = function (&$value, $key) use (&$normalize) {
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $k => &$v) {
|
||||
$convertIdContainer($v);
|
||||
$normalize($v, $k);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ($key === '_id' && is_string($value) && preg_match('/^[a-f\d]{24}$/i', $value)) {
|
||||
try {
|
||||
$value = new ObjectId($value);
|
||||
} catch (\Throwable) {
|
||||
// Ignore invalid ObjectIds
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Top-level traversal
|
||||
foreach ($filter as $k => &$v) {
|
||||
if ($k === '_id') {
|
||||
$convertIdContainer($v);
|
||||
} elseif (is_array($v)) {
|
||||
// Recurse into nested boolean operators ($and/$or) etc.
|
||||
foreach ($v as $kk => &$vv) {
|
||||
if ($kk === '_id') {
|
||||
$convertIdContainer($vv);
|
||||
} elseif (is_array($vv)) {
|
||||
foreach ($vv as $kkk => &$vvv) {
|
||||
if ($kkk === '_id') {
|
||||
$convertIdContainer($vvv);
|
||||
$normalize($v, $k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($v);
|
||||
|
||||
return $filter;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,6 +79,47 @@ class MongoConnection implements MongoConnectionInterface
|
|||
return $this->getCollection($database, $collection);
|
||||
}
|
||||
|
||||
public function upsertOne(string $database, string $collection, array $filter, array $update): string
|
||||
{
|
||||
$id = $this->generateId();
|
||||
if ($this->updateOne($database, $collection, $filter, $update) === 0) {
|
||||
$doc = $filter;
|
||||
if (isset($update['$set'])) {
|
||||
foreach ($update['$set'] as $k => $v) { $doc[$k] = $v; }
|
||||
} else {
|
||||
foreach ($update as $k => $v) { $doc[$k] = $v; }
|
||||
}
|
||||
$doc['_id'] = $doc['_id'] ?? $id;
|
||||
$this->store[$database][$collection][] = $doc;
|
||||
return (string)$doc['_id'];
|
||||
}
|
||||
$found = $this->find($database, $collection, $filter);
|
||||
$first = reset($found);
|
||||
return (string)($first['_id'] ?? '');
|
||||
}
|
||||
|
||||
public function count(string $database, string $collection, array $filter = []): int
|
||||
{
|
||||
$docs = $this->getCollection($database, $collection);
|
||||
$count = 0;
|
||||
foreach ($docs as $doc) {
|
||||
if ($this->matches($doc, $filter)) {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
public function withSession(callable $callback): mixed
|
||||
{
|
||||
return $callback($this, null);
|
||||
}
|
||||
|
||||
public function withTransaction(callable $callback): mixed
|
||||
{
|
||||
return $callback($this, null);
|
||||
}
|
||||
|
||||
private function &getCollection(string $database, string $collection): array
|
||||
{
|
||||
if (!isset($this->store[$database][$collection])) {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@ interface MongoConnectionInterface
|
|||
/** @param array<string,mixed> $filter @param array<string,mixed> $update */
|
||||
public function upsertOne(string $database, string $collection, array $filter, array $update): string;
|
||||
|
||||
/** @param array<string,mixed> $filter */
|
||||
public function count(string $database, string $collection, array $filter = []): int;
|
||||
|
||||
/** Execute a callback with a client session; callback receives the connection instance and session as args. */
|
||||
public function withSession(callable $callback): mixed;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue