diff --git a/.env b/.env index 58cdce18c..1f5de6473 100644 --- a/.env +++ b/.env @@ -19,15 +19,11 @@ APP_ENV=dev APP_SECRET= ###< symfony/framework-bundle ### -###> doctrine/doctrine-bundle ### -# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url -# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml -# -DATABASE_URL="sqlite:///%kernel.project_dir%/data/database.sqlite" -# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=8.0.32&charset=utf8mb4" -# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=10.11.2-MariaDB&charset=utf8mb4" -# DATABASE_URL="postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=16&charset=utf8" -###< doctrine/doctrine-bundle ### +###> doctrine/mongodb-odm-bundle ### +# Format described at https://www.doctrine-project.org/projects/doctrine-mongodb-bundle/en/4.4/config.html#configuration +MONGODB_URL=mongodb://localhost:27017 +MONGODB_DB=symfony_demo +###< doctrine/mongodb-odm-bundle ### ###> symfony/mailer ### MAILER_DSN=null://null diff --git a/.env.local.demo b/.env.local.demo deleted file mode 100644 index d79c676ae..000000000 --- a/.env.local.demo +++ /dev/null @@ -1,3 +0,0 @@ -# This variable is for the demo app only! -# See https://symfony.com/doc/current/reference/configuration/framework.html#configuration-framework-secret -APP_SECRET=not-a-secret--read-the-doc! diff --git a/.env.test b/.env.test index a5f73474d..ececa94ba 100644 --- a/.env.test +++ b/.env.test @@ -1,4 +1,4 @@ # Define your env variables for the test environment here KERNEL_CLASS='App\Kernel' APP_SECRET='$ecretf0rt3st' -DATABASE_URL=sqlite:///%kernel.project_dir%/data/database_test.sqlite +MONGODB_DB=symfony_demo_test diff --git a/composer.json b/composer.json index 866a74fd7..b57d7e67d 100644 --- a/composer.json +++ b/composer.json @@ -10,10 +10,8 @@ "ext-ctype": "*", "ext-iconv": "*", "ext-pdo_sqlite": "*", - "doctrine/dbal": "^4.0", - "doctrine/doctrine-bundle": "^2.16", - "doctrine/doctrine-migrations-bundle": "^3.3", - "doctrine/orm": "^3.5", + "ext-mongodb": "^1.21.2|^2.1", + "doctrine/mongodb-odm-bundle": "^5", "league/commonmark": "^2.1", "symfony/apache-pack": "^1.0", "symfony/asset": "^7", @@ -47,8 +45,8 @@ "twig/markdown-extra": "^3.3" }, "require-dev": { - "dama/doctrine-test-bundle": "^8.0.2", - "doctrine/doctrine-fixtures-bundle": "^4.1", + "doctrine/data-fixtures": "^1.7", + "phpstan/extension-installer": "^1.2", "phpstan/phpstan": "^2.0", "phpstan/phpstan-doctrine": "^2.0", "phpstan/phpstan-symfony": "^2.0", @@ -72,6 +70,7 @@ }, "config": { "allow-plugins": { + "phpstan/extension-installer": true, "symfony/flex": true, "symfony/runtime": true }, diff --git a/composer.lock b/composer.lock index 7be23b775..57ad936aa 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "47c226bcb92b5cfd3c500a3b224b8db7", + "content-hash": "5dc2f1a2852349f9e0748f011561951f", "packages": [ { "name": "composer/semver", @@ -159,35 +159,37 @@ "time": "2024-07-08T12:26:09+00:00" }, { - "name": "doctrine/collections", - "version": "2.3.0", + "name": "doctrine/cache", + "version": "2.2.0", "source": { "type": "git", - "url": "https://github.com/doctrine/collections.git", - "reference": "2eb07e5953eed811ce1b309a7478a3b236f2273d" + "url": "https://github.com/doctrine/cache.git", + "reference": "1ca8f21980e770095a31456042471a57bc4c68fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/collections/zipball/2eb07e5953eed811ce1b309a7478a3b236f2273d", - "reference": "2eb07e5953eed811ce1b309a7478a3b236f2273d", + "url": "https://api.github.com/repos/doctrine/cache/zipball/1ca8f21980e770095a31456042471a57bc4c68fb", + "reference": "1ca8f21980e770095a31456042471a57bc4c68fb", "shasum": "" }, "require": { - "doctrine/deprecations": "^1", - "php": "^8.1", - "symfony/polyfill-php84": "^1.30" + "php": "~7.1 || ^8.0" + }, + "conflict": { + "doctrine/common": ">2.2,<2.4" }, "require-dev": { - "doctrine/coding-standard": "^12", - "ext-json": "*", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-phpunit": "^1.0", - "phpunit/phpunit": "^10.5" + "cache/integration-tests": "dev-master", + "doctrine/coding-standard": "^9", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "psr/cache": "^1.0 || ^2.0 || ^3.0", + "symfony/cache": "^4.4 || ^5.4 || ^6", + "symfony/var-exporter": "^4.4 || ^5.4 || ^6" }, "type": "library", "autoload": { "psr-4": { - "Doctrine\\Common\\Collections\\": "src" + "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" } }, "notification-url": "https://packagist.org/downloads/", @@ -216,17 +218,22 @@ "email": "schmittjoh@gmail.com" } ], - "description": "PHP Doctrine Collections library that adds additional functionality on top of PHP arrays.", - "homepage": "https://www.doctrine-project.org/projects/collections.html", + "description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.", + "homepage": "https://www.doctrine-project.org/projects/cache.html", "keywords": [ - "array", - "collections", - "iterators", - "php" + "abstraction", + "apcu", + "cache", + "caching", + "couchdb", + "memcached", + "php", + "redis", + "xcache" ], "support": { - "issues": "https://github.com/doctrine/collections/issues", - "source": "https://github.com/doctrine/collections/tree/2.3.0" + "issues": "https://github.com/doctrine/cache/issues", + "source": "https://github.com/doctrine/cache/tree/2.2.0" }, "funding": [ { @@ -238,52 +245,43 @@ "type": "patreon" }, { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcollections", + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcache", "type": "tidelift" } ], - "time": "2025-03-22T10:17:19+00:00" + "abandoned": true, + "time": "2022-05-20T20:07:39+00:00" }, { - "name": "doctrine/dbal", - "version": "4.3.3", + "name": "doctrine/collections", + "version": "2.3.0", "source": { "type": "git", - "url": "https://github.com/doctrine/dbal.git", - "reference": "231959669bb2173194c95636eae7f1b41b2a8b19" + "url": "https://github.com/doctrine/collections.git", + "reference": "2eb07e5953eed811ce1b309a7478a3b236f2273d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/231959669bb2173194c95636eae7f1b41b2a8b19", - "reference": "231959669bb2173194c95636eae7f1b41b2a8b19", + "url": "https://api.github.com/repos/doctrine/collections/zipball/2eb07e5953eed811ce1b309a7478a3b236f2273d", + "reference": "2eb07e5953eed811ce1b309a7478a3b236f2273d", "shasum": "" }, "require": { - "doctrine/deprecations": "^1.1.5", - "php": "^8.2", - "psr/cache": "^1|^2|^3", - "psr/log": "^1|^2|^3" + "doctrine/deprecations": "^1", + "php": "^8.1", + "symfony/polyfill-php84": "^1.30" }, "require-dev": { - "doctrine/coding-standard": "13.0.1", - "fig/log-test": "^1", - "jetbrains/phpstorm-stubs": "2023.2", - "phpstan/phpstan": "2.1.22", - "phpstan/phpstan-phpunit": "2.0.6", - "phpstan/phpstan-strict-rules": "^2", - "phpunit/phpunit": "11.5.23", - "slevomat/coding-standard": "8.16.2", - "squizlabs/php_codesniffer": "3.13.1", - "symfony/cache": "^6.3.8|^7.0", - "symfony/console": "^5.4|^6.3|^7.0" - }, - "suggest": { - "symfony/console": "For helpful console commands such as SQL execution and import of files." + "doctrine/coding-standard": "^12", + "ext-json": "*", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^10.5" }, "type": "library", "autoload": { "psr-4": { - "Doctrine\\DBAL\\": "src" + "Doctrine\\Common\\Collections\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -306,33 +304,23 @@ { "name": "Jonathan Wage", "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" } ], - "description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.", - "homepage": "https://www.doctrine-project.org/projects/dbal.html", + "description": "PHP Doctrine Collections library that adds additional functionality on top of PHP arrays.", + "homepage": "https://www.doctrine-project.org/projects/collections.html", "keywords": [ - "abstraction", - "database", - "db2", - "dbal", - "mariadb", - "mssql", - "mysql", - "oci8", - "oracle", - "pdo", - "pgsql", - "postgresql", - "queryobject", - "sasql", - "sql", - "sqlite", - "sqlserver", - "sqlsrv" - ], - "support": { - "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/4.3.3" + "array", + "collections", + "iterators", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/collections/issues", + "source": "https://github.com/doctrine/collections/tree/2.3.0" }, "funding": [ { @@ -344,11 +332,11 @@ "type": "patreon" }, { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdbal", + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcollections", "type": "tidelift" } ], - "time": "2025-09-04T23:52:42+00:00" + "time": "2025-03-22T10:17:19+00:00" }, { "name": "doctrine/deprecations", @@ -398,213 +386,6 @@ }, "time": "2025-04-07T20:06:18+00:00" }, - { - "name": "doctrine/doctrine-bundle", - "version": "2.16.2", - "source": { - "type": "git", - "url": "https://github.com/doctrine/DoctrineBundle.git", - "reference": "1c10de0fe995f01eca6b073d1c2549ef0b603a7f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/1c10de0fe995f01eca6b073d1c2549ef0b603a7f", - "reference": "1c10de0fe995f01eca6b073d1c2549ef0b603a7f", - "shasum": "" - }, - "require": { - "doctrine/dbal": "^3.7.0 || ^4.0", - "doctrine/persistence": "^3.1 || ^4", - "doctrine/sql-formatter": "^1.0.1", - "php": "^8.1", - "symfony/cache": "^6.4 || ^7.0", - "symfony/config": "^6.4 || ^7.0", - "symfony/console": "^6.4 || ^7.0", - "symfony/dependency-injection": "^6.4 || ^7.0", - "symfony/deprecation-contracts": "^2.1 || ^3", - "symfony/doctrine-bridge": "^6.4.3 || ^7.0.3", - "symfony/framework-bundle": "^6.4 || ^7.0", - "symfony/service-contracts": "^2.5 || ^3" - }, - "conflict": { - "doctrine/annotations": ">=3.0", - "doctrine/cache": "< 1.11", - "doctrine/orm": "<2.17 || >=4.0", - "symfony/var-exporter": "< 6.4.1 || 7.0.0", - "twig/twig": "<2.13 || >=3.0 <3.0.4" - }, - "require-dev": { - "doctrine/annotations": "^1 || ^2", - "doctrine/cache": "^1.11 || ^2.0", - "doctrine/coding-standard": "^13", - "doctrine/deprecations": "^1.0", - "doctrine/orm": "^2.17 || ^3.1", - "friendsofphp/proxy-manager-lts": "^1.0", - "phpstan/phpstan": "2.1.1", - "phpstan/phpstan-phpunit": "2.0.3", - "phpstan/phpstan-strict-rules": "^2", - "phpunit/phpunit": "^10.5.53", - "psr/log": "^1.1.4 || ^2.0 || ^3.0", - "symfony/doctrine-messenger": "^6.4 || ^7.0", - "symfony/expression-language": "^6.4 || ^7.0", - "symfony/messenger": "^6.4 || ^7.0", - "symfony/property-info": "^6.4 || ^7.0", - "symfony/security-bundle": "^6.4 || ^7.0", - "symfony/stopwatch": "^6.4 || ^7.0", - "symfony/string": "^6.4 || ^7.0", - "symfony/twig-bridge": "^6.4 || ^7.0", - "symfony/validator": "^6.4 || ^7.0", - "symfony/var-exporter": "^6.4.1 || ^7.0.1", - "symfony/web-profiler-bundle": "^6.4 || ^7.0", - "symfony/yaml": "^6.4 || ^7.0", - "twig/twig": "^2.13 || ^3.0.4" - }, - "suggest": { - "doctrine/orm": "The Doctrine ORM integration is optional in the bundle.", - "ext-pdo": "*", - "symfony/web-profiler-bundle": "To use the data collector." - }, - "type": "symfony-bundle", - "autoload": { - "psr-4": { - "Doctrine\\Bundle\\DoctrineBundle\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - }, - { - "name": "Doctrine Project", - "homepage": "https://www.doctrine-project.org/" - } - ], - "description": "Symfony DoctrineBundle", - "homepage": "https://www.doctrine-project.org", - "keywords": [ - "database", - "dbal", - "orm", - "persistence" - ], - "support": { - "issues": "https://github.com/doctrine/DoctrineBundle/issues", - "source": "https://github.com/doctrine/DoctrineBundle/tree/2.16.2" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdoctrine-bundle", - "type": "tidelift" - } - ], - "time": "2025-09-10T19:14:48+00:00" - }, - { - "name": "doctrine/doctrine-migrations-bundle", - "version": "3.4.2", - "source": { - "type": "git", - "url": "https://github.com/doctrine/DoctrineMigrationsBundle.git", - "reference": "5a6ac7120c2924c4c070a869d08b11ccf9e277b9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineMigrationsBundle/zipball/5a6ac7120c2924c4c070a869d08b11ccf9e277b9", - "reference": "5a6ac7120c2924c4c070a869d08b11ccf9e277b9", - "shasum": "" - }, - "require": { - "doctrine/doctrine-bundle": "^2.4", - "doctrine/migrations": "^3.2", - "php": "^7.2 || ^8.0", - "symfony/deprecation-contracts": "^2.1 || ^3", - "symfony/framework-bundle": "^5.4 || ^6.0 || ^7.0" - }, - "require-dev": { - "composer/semver": "^3.0", - "doctrine/coding-standard": "^12", - "doctrine/orm": "^2.6 || ^3", - "phpstan/phpstan": "^1.4 || ^2", - "phpstan/phpstan-deprecation-rules": "^1 || ^2", - "phpstan/phpstan-phpunit": "^1 || ^2", - "phpstan/phpstan-strict-rules": "^1.1 || ^2", - "phpstan/phpstan-symfony": "^1.3 || ^2", - "phpunit/phpunit": "^8.5 || ^9.5", - "symfony/phpunit-bridge": "^6.3 || ^7", - "symfony/var-exporter": "^5.4 || ^6 || ^7" - }, - "type": "symfony-bundle", - "autoload": { - "psr-4": { - "Doctrine\\Bundle\\MigrationsBundle\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Doctrine Project", - "homepage": "https://www.doctrine-project.org" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony DoctrineMigrationsBundle", - "homepage": "https://www.doctrine-project.org", - "keywords": [ - "dbal", - "migrations", - "schema" - ], - "support": { - "issues": "https://github.com/doctrine/DoctrineMigrationsBundle/issues", - "source": "https://github.com/doctrine/DoctrineMigrationsBundle/tree/3.4.2" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdoctrine-migrations-bundle", - "type": "tidelift" - } - ], - "time": "2025-03-11T17:36:26+00:00" - }, { "name": "doctrine/event-manager", "version": "2.0.1", @@ -696,96 +477,6 @@ ], "time": "2024-05-22T20:47:39+00:00" }, - { - "name": "doctrine/inflector", - "version": "2.1.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/inflector.git", - "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/6d6c96277ea252fc1304627204c3d5e6e15faa3b", - "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "require-dev": { - "doctrine/coding-standard": "^12.0 || ^13.0", - "phpstan/phpstan": "^1.12 || ^2.0", - "phpstan/phpstan-phpunit": "^1.4 || ^2.0", - "phpstan/phpstan-strict-rules": "^1.6 || ^2.0", - "phpunit/phpunit": "^8.5 || ^12.2" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Inflector\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.", - "homepage": "https://www.doctrine-project.org/projects/inflector.html", - "keywords": [ - "inflection", - "inflector", - "lowercase", - "manipulation", - "php", - "plural", - "singular", - "strings", - "uppercase", - "words" - ], - "support": { - "issues": "https://github.com/doctrine/inflector/issues", - "source": "https://github.com/doctrine/inflector/tree/2.1.0" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector", - "type": "tidelift" - } - ], - "time": "2025-08-10T19:31:58+00:00" - }, { "name": "doctrine/instantiator", "version": "2.0.0", @@ -934,61 +625,61 @@ "time": "2024-02-05T11:56:58+00:00" }, { - "name": "doctrine/migrations", - "version": "3.9.4", + "name": "doctrine/mongodb-odm", + "version": "2.12.2", "source": { "type": "git", - "url": "https://github.com/doctrine/migrations.git", - "reference": "1b88fcb812f2cd6e77c83d16db60e3cf1e35c66c" + "url": "https://github.com/doctrine/mongodb-odm.git", + "reference": "7abdc70f9cabbc44dae0771467dc603acad2797e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/migrations/zipball/1b88fcb812f2cd6e77c83d16db60e3cf1e35c66c", - "reference": "1b88fcb812f2cd6e77c83d16db60e3cf1e35c66c", + "url": "https://api.github.com/repos/doctrine/mongodb-odm/zipball/7abdc70f9cabbc44dae0771467dc603acad2797e", + "reference": "7abdc70f9cabbc44dae0771467dc603acad2797e", "shasum": "" }, "require": { - "composer-runtime-api": "^2", - "doctrine/dbal": "^3.6 || ^4", - "doctrine/deprecations": "^0.5.3 || ^1", - "doctrine/event-manager": "^1.2 || ^2.0", + "doctrine/cache": "^1.11 || ^2.0", + "doctrine/collections": "^1.5 || ^2.0", + "doctrine/event-manager": "^1.0 || ^2.0", + "doctrine/instantiator": "^1.1 || ^2", + "doctrine/persistence": "^3.2 || ^4", + "ext-mongodb": "^1.21 || ^2.0", + "friendsofphp/proxy-manager-lts": "^1.0", + "jean85/pretty-package-versions": "^1.3.0 || ^2.0.1", + "mongodb/mongodb": "^1.21.2 || ^2.1.1", "php": "^8.1", - "psr/log": "^1.1.3 || ^2 || ^3", + "psr/cache": "^1.0 || ^2.0 || ^3.0", "symfony/console": "^5.4 || ^6.0 || ^7.0", - "symfony/stopwatch": "^5.4 || ^6.0 || ^7.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0", + "symfony/var-dumper": "^5.4 || ^6.0 || ^7.0", "symfony/var-exporter": "^6.2 || ^7.0" }, "conflict": { - "doctrine/orm": "<2.12 || >=4" + "doctrine/annotations": "<1.12 || >=3.0" }, "require-dev": { - "doctrine/coding-standard": "^13", - "doctrine/orm": "^2.13 || ^3", - "doctrine/persistence": "^2 || ^3 || ^4", - "doctrine/sql-formatter": "^1.0", - "ext-pdo_sqlite": "*", - "fig/log-test": "^1", - "phpstan/phpstan": "^2", - "phpstan/phpstan-deprecation-rules": "^2", - "phpstan/phpstan-phpunit": "^2", - "phpstan/phpstan-strict-rules": "^2", - "phpstan/phpstan-symfony": "^2", - "phpunit/phpunit": "^10.3 || ^11.0 || ^12.0", - "symfony/cache": "^5.4 || ^6.0 || ^7.0", - "symfony/process": "^5.4 || ^6.0 || ^7.0", - "symfony/yaml": "^5.4 || ^6.0 || ^7.0" + "doctrine/annotations": "^1.12 || ^2.0", + "doctrine/coding-standard": "^12.0", + "doctrine/orm": "^3.2", + "ext-bcmath": "*", + "jmikola/geojson": "^1.0", + "phpbench/phpbench": "^1.0.0", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^10.4", + "squizlabs/php_codesniffer": "^3.5", + "symfony/cache": "^5.4 || ^6.0 || ^7.0" }, "suggest": { - "doctrine/sql-formatter": "Allows to generate formatted SQL with the diff command.", - "symfony/yaml": "Allows the use of yaml for migration configuration files." + "doctrine/annotations": "For annotation mapping support", + "ext-bcmath": "Decimal128 type support" }, - "bin": [ - "bin/doctrine-migrations" - ], "type": "library", "autoload": { "psr-4": { - "Doctrine\\Migrations\\": "src" + "Doctrine\\ODM\\MongoDB\\": "lib/Doctrine/ODM/MongoDB" } }, "notification-url": "https://packagist.org/downloads/", @@ -997,28 +688,40 @@ ], "authors": [ { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" + "name": "Jeremy Mikola", + "email": "jmikola@gmail.com" }, { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" + "name": "Maciej Malarz", + "email": "malarzm@gmail.com" }, { - "name": "Michael Simonson", - "email": "contact@mikesimonson.com" + "name": "Andreas Braun", + "email": "alcaeus@alcaeus.org" + }, + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Fran Moreno", + "email": "franmomu@gmail.com" } ], - "description": "PHP Doctrine Migrations project offer additional functionality on top of the database abstraction layer (DBAL) for versioning your database schema and easily deploying changes to it. It is a very easy to use and a powerful tool.", - "homepage": "https://www.doctrine-project.org/projects/migrations.html", + "description": "PHP Doctrine MongoDB Object Document Mapper (ODM) provides transparent persistence for PHP objects to MongoDB.", + "homepage": "https://www.doctrine-project.org/projects/mongodb-odm.html", "keywords": [ - "database", - "dbal", - "migrations" + "data", + "mapper", + "mapping", + "mongodb", + "object", + "odm", + "php" ], "support": { - "issues": "https://github.com/doctrine/migrations/issues", - "source": "https://github.com/doctrine/migrations/tree/3.9.4" + "issues": "https://github.com/doctrine/mongodb-odm/issues", + "source": "https://github.com/doctrine/mongodb-odm/tree/2.12.2" }, "funding": [ { @@ -1030,62 +733,133 @@ "type": "patreon" }, { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fmigrations", + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fmongodb-odm", "type": "tidelift" } ], - "time": "2025-08-19T06:41:07+00:00" + "time": "2025-09-26T07:35:47+00:00" }, { - "name": "doctrine/orm", - "version": "3.5.2", + "name": "doctrine/mongodb-odm-bundle", + "version": "5.4.1", "source": { "type": "git", - "url": "https://github.com/doctrine/orm.git", - "reference": "5a541b8b3a327ab1ea5f93b1615b4ff67a34e109" + "url": "https://github.com/doctrine/DoctrineMongoDBBundle.git", + "reference": "739c432ca8bdd10892a7df65602a8b79d7205bbd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/5a541b8b3a327ab1ea5f93b1615b4ff67a34e109", - "reference": "5a541b8b3a327ab1ea5f93b1615b4ff67a34e109", + "url": "https://api.github.com/repos/doctrine/DoctrineMongoDBBundle/zipball/739c432ca8bdd10892a7df65602a8b79d7205bbd", + "reference": "739c432ca8bdd10892a7df65602a8b79d7205bbd", "shasum": "" }, "require": { - "composer-runtime-api": "^2", - "doctrine/collections": "^2.2", - "doctrine/dbal": "^3.8.2 || ^4", - "doctrine/deprecations": "^0.5.3 || ^1", - "doctrine/event-manager": "^1.2 || ^2", - "doctrine/inflector": "^1.4 || ^2.0", - "doctrine/instantiator": "^1.3 || ^2", - "doctrine/lexer": "^3", - "doctrine/persistence": "^3.3.1 || ^4", - "ext-ctype": "*", + "composer-runtime-api": "^2.0", + "doctrine/mongodb-odm": "^2.6", + "doctrine/persistence": "^3.0 || ^4.0", + "ext-mongodb": "^1.21 || ^2", "php": "^8.1", - "psr/cache": "^1 || ^2 || ^3", - "symfony/console": "^5.4 || ^6.0 || ^7.0", - "symfony/var-exporter": "^6.3.9 || ^7.0" + "psr/log": "^1.0 || ^2.0 || ^3.0", + "symfony/config": "^6.4 || ^7.0", + "symfony/console": "^6.4 || ^7.0", + "symfony/dependency-injection": "^6.4 || ^7.0", + "symfony/doctrine-bridge": "^6.4 || ^7.0", + "symfony/framework-bundle": "^6.4 || ^7.0", + "symfony/http-kernel": "^6.4 || ^7.0", + "symfony/options-resolver": "^6.4 || ^7.0" + }, + "conflict": { + "doctrine/data-fixtures": "<1.8 || >=3" }, "require-dev": { - "doctrine/coding-standard": "^13.0", - "phpbench/phpbench": "^1.0", - "phpdocumentor/guides-cli": "^1.4", - "phpstan/extension-installer": "^1.4", - "phpstan/phpstan": "2.0.3", - "phpstan/phpstan-deprecation-rules": "^2", - "phpunit/phpunit": "^10.4.0", - "psr/log": "^1 || ^2 || ^3", - "squizlabs/php_codesniffer": "3.12.0", - "symfony/cache": "^5.4 || ^6.2 || ^7.0" + "composer/semver": "^3.4", + "doctrine/coding-standard": "^11.0", + "doctrine/data-fixtures": "^1.8 || ^2.0", + "phpstan/phpstan": "^2.1", + "phpunit/phpunit": "^10.5", + "symfony/browser-kit": "^6.4 || ^7.0", + "symfony/form": "^6.4 || ^7.0", + "symfony/phpunit-bridge": "^6.4.1 || ^7.0.1", + "symfony/security-bundle": "^6.4 || ^7.0", + "symfony/stopwatch": "^6.4 || ^7.0", + "symfony/validator": "^6.4 || ^7.0", + "symfony/yaml": "^6.4 || ^7.0" }, "suggest": { - "ext-dom": "Provides support for XSD validation for XML mapping files", - "symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0" + "doctrine/data-fixtures": "Load data fixtures" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Doctrine\\Bundle\\MongoDBBundle\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bulat Shakirzyanov", + "email": "mallluhuct@gmail.com" + }, + { + "name": "Kris Wallsmith", + "email": "kris@symfony.com" + }, + { + "name": "Jonathan H. Wage", + "email": "jonwage@gmail.com" + } + ], + "description": "Symfony Doctrine MongoDB Bundle", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "mongodb", + "persistence", + "symfony" + ], + "support": { + "issues": "https://github.com/doctrine/DoctrineMongoDBBundle/issues", + "source": "https://github.com/doctrine/DoctrineMongoDBBundle/tree/5.4.1" + }, + "time": "2025-09-04T21:46:29+00:00" + }, + { + "name": "doctrine/persistence", + "version": "3.4.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/persistence.git", + "reference": "23069c8cfc19d7825e9fbe3341227d8c51eff2bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/persistence/zipball/23069c8cfc19d7825e9fbe3341227d8c51eff2bc", + "reference": "23069c8cfc19d7825e9fbe3341227d8c51eff2bc", + "shasum": "" + }, + "require": { + "doctrine/event-manager": "^1 || ^2", + "php": "^7.2 || ^8.0", + "psr/cache": "^1.0 || ^2.0 || ^3.0" + }, + "conflict": { + "doctrine/common": "<2.10" + }, + "require-dev": { + "doctrine/coding-standard": "^12", + "doctrine/common": "^3.0", + "phpstan/phpstan": "1.12.7", + "phpstan/phpstan-phpunit": "^1", + "phpstan/phpstan-strict-rules": "^1.1", + "phpunit/phpunit": "^8.5.38 || ^9.5", + "symfony/cache": "^4.4 || ^5.4 || ^6.0 || ^7.0" }, "type": "library", "autoload": { "psr-4": { - "Doctrine\\ORM\\": "src" + "Doctrine\\Persistence\\": "src/Persistence" } }, "notification-url": "https://packagist.org/downloads/", @@ -1110,54 +884,150 @@ "email": "jonwage@gmail.com" }, { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "The Doctrine Persistence project is a set of shared interfaces and functionality that the different Doctrine object mappers share.", + "homepage": "https://www.doctrine-project.org/projects/persistence.html", + "keywords": [ + "mapper", + "object", + "odm", + "orm", + "persistence" + ], + "support": { + "issues": "https://github.com/doctrine/persistence/issues", + "source": "https://github.com/doctrine/persistence/tree/3.4.1" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fpersistence", + "type": "tidelift" + } + ], + "time": "2025-09-29T06:33:58+00:00" + }, + { + "name": "egulias/email-validator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/egulias/EmailValidator.git", + "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", + "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^2.0 || ^3.0", + "php": ">=8.1", + "symfony/polyfill-intl-idn": "^1.26" + }, + "require-dev": { + "phpunit/phpunit": "^10.2", + "vimeo/psalm": "^5.12" + }, + "suggest": { + "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Egulias\\EmailValidator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eduardo Gulias Davis" } ], - "description": "Object-Relational-Mapper for PHP", - "homepage": "https://www.doctrine-project.org/projects/orm.html", + "description": "A library for validating emails against several RFCs", + "homepage": "https://github.com/egulias/EmailValidator", "keywords": [ - "database", - "orm" + "email", + "emailvalidation", + "emailvalidator", + "validation", + "validator" ], "support": { - "issues": "https://github.com/doctrine/orm/issues", - "source": "https://github.com/doctrine/orm/tree/3.5.2" + "issues": "https://github.com/egulias/EmailValidator/issues", + "source": "https://github.com/egulias/EmailValidator/tree/4.0.4" }, - "time": "2025-08-08T17:00:40+00:00" + "funding": [ + { + "url": "https://github.com/egulias", + "type": "github" + } + ], + "time": "2025-03-06T22:45:56+00:00" }, { - "name": "doctrine/persistence", - "version": "4.1.0", + "name": "friendsofphp/proxy-manager-lts", + "version": "v1.0.18", "source": { "type": "git", - "url": "https://github.com/doctrine/persistence.git", - "reference": "dcbdfe4b211ae09478e192289cae7ab0987b29a4" + "url": "https://github.com/FriendsOfPHP/proxy-manager-lts.git", + "reference": "2c8a6cffc3220e99352ad958fe7cf06bf6f7690f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/persistence/zipball/dcbdfe4b211ae09478e192289cae7ab0987b29a4", - "reference": "dcbdfe4b211ae09478e192289cae7ab0987b29a4", + "url": "https://api.github.com/repos/FriendsOfPHP/proxy-manager-lts/zipball/2c8a6cffc3220e99352ad958fe7cf06bf6f7690f", + "reference": "2c8a6cffc3220e99352ad958fe7cf06bf6f7690f", "shasum": "" }, "require": { - "doctrine/event-manager": "^1 || ^2", - "php": "^8.1", - "psr/cache": "^1.0 || ^2.0 || ^3.0" + "laminas/laminas-code": "~3.4.1|^4.0", + "php": ">=7.1", + "symfony/filesystem": "^4.4.17|^5.0|^6.0|^7.0" + }, + "conflict": { + "laminas/laminas-stdlib": "<3.2.1", + "zendframework/zend-stdlib": "<3.2.1" + }, + "replace": { + "ocramius/proxy-manager": "^2.1" }, "require-dev": { - "doctrine/coding-standard": "^12", - "phpstan/phpstan": "1.12.7", - "phpstan/phpstan-phpunit": "^1", - "phpstan/phpstan-strict-rules": "^1.6", - "phpunit/phpunit": "^9.6", - "symfony/cache": "^4.4 || ^5.4 || ^6.0 || ^7.0", - "symfony/finder": "^4.4 || ^5.4 || ^6.0 || ^7.0" + "ext-phar": "*", + "symfony/phpunit-bridge": "^5.4|^6.0|^7.0" }, "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/Ocramius/ProxyManager", + "name": "ocramius/proxy-manager" + } + }, "autoload": { "psr-4": { - "Doctrine\\Persistence\\": "src/Persistence" + "ProxyManager\\": "src/ProxyManager" } }, "notification-url": "https://packagist.org/downloads/", @@ -1166,89 +1036,75 @@ ], "authors": [ { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "https://ocramius.github.io/" }, { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" } ], - "description": "The Doctrine Persistence project is a set of shared interfaces and functionality that the different Doctrine object mappers share.", - "homepage": "https://www.doctrine-project.org/projects/persistence.html", + "description": "Adding support for a wider range of PHP versions to ocramius/proxy-manager", + "homepage": "https://github.com/FriendsOfPHP/proxy-manager-lts", "keywords": [ - "mapper", - "object", - "odm", - "orm", - "persistence" + "aop", + "lazy loading", + "proxy", + "proxy pattern", + "service proxies" ], "support": { - "issues": "https://github.com/doctrine/persistence/issues", - "source": "https://github.com/doctrine/persistence/tree/4.1.0" + "issues": "https://github.com/FriendsOfPHP/proxy-manager-lts/issues", + "source": "https://github.com/FriendsOfPHP/proxy-manager-lts/tree/v1.0.18" }, "funding": [ { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" + "url": "https://github.com/Ocramius", + "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fpersistence", + "url": "https://tidelift.com/funding/github/packagist/ocramius/proxy-manager", "type": "tidelift" } ], - "time": "2025-08-21T16:00:31+00:00" + "time": "2024-03-20T12:50:41+00:00" }, { - "name": "doctrine/sql-formatter", - "version": "1.5.2", + "name": "jean85/pretty-package-versions", + "version": "2.1.1", "source": { "type": "git", - "url": "https://github.com/doctrine/sql-formatter.git", - "reference": "d6d00aba6fd2957fe5216fe2b7673e9985db20c8" + "url": "https://github.com/Jean85/pretty-package-versions.git", + "reference": "4d7aa5dab42e2a76d99559706022885de0e18e1a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/sql-formatter/zipball/d6d00aba6fd2957fe5216fe2b7673e9985db20c8", - "reference": "d6d00aba6fd2957fe5216fe2b7673e9985db20c8", + "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/4d7aa5dab42e2a76d99559706022885de0e18e1a", + "reference": "4d7aa5dab42e2a76d99559706022885de0e18e1a", "shasum": "" }, "require": { - "php": "^8.1" + "composer-runtime-api": "^2.1.0", + "php": "^7.4|^8.0" }, "require-dev": { - "doctrine/coding-standard": "^12", - "ergebnis/phpunit-slow-test-detector": "^2.14", - "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^10.5" + "friendsofphp/php-cs-fixer": "^3.2", + "jean85/composer-provided-replaced-stub-package": "^1.0", + "phpstan/phpstan": "^2.0", + "phpunit/phpunit": "^7.5|^8.5|^9.6", + "rector/rector": "^2.0", + "vimeo/psalm": "^4.3 || ^5.0" }, - "bin": [ - "bin/sql-formatter" - ], "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, "autoload": { "psr-4": { - "Doctrine\\SqlFormatter\\": "src" + "Jean85\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1257,89 +1113,85 @@ ], "authors": [ { - "name": "Jeremy Dorn", - "email": "jeremy@jeremydorn.com", - "homepage": "https://jeremydorn.com/" + "name": "Alessandro Lai", + "email": "alessandro.lai85@gmail.com" } ], - "description": "a PHP SQL highlighting library", - "homepage": "https://github.com/doctrine/sql-formatter/", + "description": "A library to get pretty versions strings of installed dependencies", "keywords": [ - "highlight", - "sql" + "composer", + "package", + "release", + "versions" ], "support": { - "issues": "https://github.com/doctrine/sql-formatter/issues", - "source": "https://github.com/doctrine/sql-formatter/tree/1.5.2" + "issues": "https://github.com/Jean85/pretty-package-versions/issues", + "source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.1" }, - "time": "2025-01-24T11:45:48+00:00" + "time": "2025-03-19T14:43:43+00:00" }, { - "name": "egulias/email-validator", - "version": "4.0.4", + "name": "laminas/laminas-code", + "version": "4.16.0", "source": { "type": "git", - "url": "https://github.com/egulias/EmailValidator.git", - "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa" + "url": "https://github.com/laminas/laminas-code.git", + "reference": "1793e78dad4108b594084d05d1fb818b85b110af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", - "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", + "url": "https://api.github.com/repos/laminas/laminas-code/zipball/1793e78dad4108b594084d05d1fb818b85b110af", + "reference": "1793e78dad4108b594084d05d1fb818b85b110af", "shasum": "" }, "require": { - "doctrine/lexer": "^2.0 || ^3.0", - "php": ">=8.1", - "symfony/polyfill-intl-idn": "^1.26" + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" }, "require-dev": { - "phpunit/phpunit": "^10.2", - "vimeo/psalm": "^5.12" + "doctrine/annotations": "^2.0.1", + "ext-phar": "*", + "laminas/laminas-coding-standard": "^3.0.0", + "laminas/laminas-stdlib": "^3.18.0", + "phpunit/phpunit": "^10.5.37", + "psalm/plugin-phpunit": "^0.19.0", + "vimeo/psalm": "^5.15.0" }, "suggest": { - "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" + "doctrine/annotations": "Doctrine\\Common\\Annotations >=1.0 for annotation features", + "laminas/laminas-stdlib": "Laminas\\Stdlib component" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0.x-dev" - } - }, "autoload": { "psr-4": { - "Egulias\\EmailValidator\\": "src" + "Laminas\\Code\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" - ], - "authors": [ - { - "name": "Eduardo Gulias Davis" - } + "BSD-3-Clause" ], - "description": "A library for validating emails against several RFCs", - "homepage": "https://github.com/egulias/EmailValidator", + "description": "Extensions to the PHP Reflection API, static code scanning, and code generation", + "homepage": "https://laminas.dev", "keywords": [ - "email", - "emailvalidation", - "emailvalidator", - "validation", - "validator" + "code", + "laminas", + "laminasframework" ], "support": { - "issues": "https://github.com/egulias/EmailValidator/issues", - "source": "https://github.com/egulias/EmailValidator/tree/4.0.4" + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-code/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-code/issues", + "rss": "https://github.com/laminas/laminas-code/releases.atom", + "source": "https://github.com/laminas/laminas-code" }, "funding": [ { - "url": "https://github.com/egulias", - "type": "github" + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" } ], - "time": "2025-03-06T22:45:56+00:00" + "time": "2024-11-20T13:15:13+00:00" }, { "name": "league/commonmark", @@ -1771,6 +1623,83 @@ }, "time": "2025-07-25T09:04:22+00:00" }, + { + "name": "mongodb/mongodb", + "version": "2.1.1", + "source": { + "type": "git", + "url": "https://github.com/mongodb/mongo-php-library.git", + "reference": "f399d24905dd42f97dfe0af9706129743ef247ac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mongodb/mongo-php-library/zipball/f399d24905dd42f97dfe0af9706129743ef247ac", + "reference": "f399d24905dd42f97dfe0af9706129743ef247ac", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.0", + "ext-mongodb": "^2.1", + "php": "^8.1", + "psr/log": "^1.1.4|^2|^3", + "symfony/polyfill-php85": "^1.32" + }, + "replace": { + "mongodb/builder": "*" + }, + "require-dev": { + "doctrine/coding-standard": "^12.0", + "phpunit/phpunit": "^10.5.35", + "rector/rector": "^1.2", + "squizlabs/php_codesniffer": "^3.7", + "vimeo/psalm": "6.5.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "MongoDB\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Andreas Braun", + "email": "andreas.braun@mongodb.com" + }, + { + "name": "Jeremy Mikola", + "email": "jmikola@gmail.com" + }, + { + "name": "Jérôme Tamarelle", + "email": "jerome.tamarelle@mongodb.com" + } + ], + "description": "MongoDB driver library", + "homepage": "https://jira.mongodb.org/browse/PHPLIB", + "keywords": [ + "database", + "driver", + "mongodb", + "persistence" + ], + "support": { + "issues": "https://github.com/mongodb/mongo-php-library/issues", + "source": "https://github.com/mongodb/mongo-php-library/tree/2.1.1" + }, + "time": "2025-08-13T20:50:05+00:00" + }, { "name": "monolog/monolog", "version": "3.9.0", @@ -5801,7 +5730,87 @@ "type": "tidelift" } ], - "time": "2025-06-24T13:30:11+00:00" + "time": "2025-06-24T13:30:11+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" }, { "name": "symfony/process", @@ -6725,68 +6734,6 @@ ], "time": "2025-08-27T15:25:48+00:00" }, - { - "name": "symfony/stopwatch", - "version": "v7.3.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/stopwatch.git", - "reference": "5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd", - "reference": "5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/service-contracts": "^2.5|^3" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Stopwatch\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides a way to profile code", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/stopwatch/tree/v7.3.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2025-02-24T10:49:57+00:00" - }, { "name": "symfony/string", "version": "v7.3.4", @@ -8364,93 +8311,25 @@ } ], "packages-dev": [ - { - "name": "dama/doctrine-test-bundle", - "version": "v8.3.1", - "source": { - "type": "git", - "url": "https://github.com/dmaicher/doctrine-test-bundle.git", - "reference": "9bc47e02a0d67cbfef6773837249f71e65c95bf6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dmaicher/doctrine-test-bundle/zipball/9bc47e02a0d67cbfef6773837249f71e65c95bf6", - "reference": "9bc47e02a0d67cbfef6773837249f71e65c95bf6", - "shasum": "" - }, - "require": { - "doctrine/dbal": "^3.3 || ^4.0", - "doctrine/doctrine-bundle": "^2.11.0", - "php": ">= 8.1", - "psr/cache": "^2.0 || ^3.0", - "symfony/cache": "^6.4 || ^7.2 || ^8.0", - "symfony/framework-bundle": "^6.4 || ^7.2 || ^8.0" - }, - "conflict": { - "phpunit/phpunit": "<10.0" - }, - "require-dev": { - "behat/behat": "^3.0", - "friendsofphp/php-cs-fixer": "^3.27", - "phpstan/phpstan": "^2.0", - "phpunit/phpunit": "^10.0 || ^11.0 || ^12.0", - "symfony/process": "^6.4 || ^7.2 || ^8.0", - "symfony/yaml": "^6.4 || ^7.2 || ^8.0" - }, - "type": "symfony-bundle", - "extra": { - "branch-alias": { - "dev-master": "8.x-dev" - } - }, - "autoload": { - "psr-4": { - "DAMA\\DoctrineTestBundle\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "David Maicher", - "email": "mail@dmaicher.de" - } - ], - "description": "Symfony bundle to isolate doctrine database tests and improve test performance", - "keywords": [ - "doctrine", - "isolation", - "performance", - "symfony", - "testing", - "tests" - ], - "support": { - "issues": "https://github.com/dmaicher/doctrine-test-bundle/issues", - "source": "https://github.com/dmaicher/doctrine-test-bundle/tree/v8.3.1" - }, - "time": "2025-08-05T17:55:02+00:00" - }, { "name": "doctrine/data-fixtures", - "version": "2.1.0", + "version": "1.8.2", "source": { "type": "git", "url": "https://github.com/doctrine/data-fixtures.git", - "reference": "f161e20f04ba5440a09330e156b40f04dd70d47f" + "reference": "6fb221da56dae2011b33d47508e3b8aeb1d91db5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/data-fixtures/zipball/f161e20f04ba5440a09330e156b40f04dd70d47f", - "reference": "f161e20f04ba5440a09330e156b40f04dd70d47f", + "url": "https://api.github.com/repos/doctrine/data-fixtures/zipball/6fb221da56dae2011b33d47508e3b8aeb1d91db5", + "reference": "6fb221da56dae2011b33d47508e3b8aeb1d91db5", "shasum": "" }, "require": { - "doctrine/persistence": "^3.1 || ^4.0", - "php": "^8.1", - "psr/log": "^1.1 || ^2 || ^3" + "doctrine/deprecations": "^0.5.3 || ^1.0", + "doctrine/persistence": "^2.0 || ^3.0", + "php": "^7.4 || ^8.0", + "symfony/polyfill-php80": "^1" }, "conflict": { "doctrine/dbal": "<3.5 || >=5", @@ -8458,6 +8337,7 @@ "doctrine/phpcr-odm": "<1.3.0" }, "require-dev": { + "doctrine/annotations": "^1.12 || ^2", "doctrine/coding-standard": "^13", "doctrine/dbal": "^3.5 || ^4", "doctrine/mongodb-odm": "^1.3.0 || ^2.0.0", @@ -8465,9 +8345,10 @@ "ext-sqlite3": "*", "fig/log-test": "^1", "phpstan/phpstan": "2.1.17", - "phpunit/phpunit": "10.5.45", - "symfony/cache": "^6.4 || ^7", - "symfony/var-exporter": "^6.4 || ^7" + "phpunit/phpunit": "^9.6.13 || 10.5.45", + "psr/log": "^1.1 || ^2 || ^3", + "symfony/cache": "^5.4 || ^6.3 || ^7", + "symfony/var-exporter": "^5.4 || ^6.3 || ^7" }, "suggest": { "alcaeus/mongo-php-adapter": "For using MongoDB ODM 1.3 with PHP 7 (deprecated)", @@ -8498,7 +8379,7 @@ ], "support": { "issues": "https://github.com/doctrine/data-fixtures/issues", - "source": "https://github.com/doctrine/data-fixtures/tree/2.1.0" + "source": "https://github.com/doctrine/data-fixtures/tree/1.8.2" }, "funding": [ { @@ -8514,48 +8395,36 @@ "type": "tidelift" } ], - "time": "2025-07-08T17:48:20+00:00" + "time": "2025-06-10T07:00:05+00:00" }, { - "name": "doctrine/doctrine-fixtures-bundle", - "version": "4.1.0", + "name": "doctrine/inflector", + "version": "2.1.0", "source": { "type": "git", - "url": "https://github.com/doctrine/DoctrineFixturesBundle.git", - "reference": "a06db6b81ff20a2980bf92063d80c013bb8b4b7c" + "url": "https://github.com/doctrine/inflector.git", + "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineFixturesBundle/zipball/a06db6b81ff20a2980bf92063d80c013bb8b4b7c", - "reference": "a06db6b81ff20a2980bf92063d80c013bb8b4b7c", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/6d6c96277ea252fc1304627204c3d5e6e15faa3b", + "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b", "shasum": "" }, "require": { - "doctrine/data-fixtures": "^2.0", - "doctrine/doctrine-bundle": "^2.2", - "doctrine/orm": "^2.14.0 || ^3.0", - "doctrine/persistence": "^2.4 || ^3.0 || ^4.0", - "php": "^8.1", - "psr/log": "^2 || ^3", - "symfony/config": "^6.4 || ^7.0", - "symfony/console": "^6.4 || ^7.0", - "symfony/dependency-injection": "^6.4 || ^7.0", - "symfony/deprecation-contracts": "^2.1 || ^3", - "symfony/doctrine-bridge": "^6.4.16 || ^7.1.9", - "symfony/http-kernel": "^6.4 || ^7.0" - }, - "conflict": { - "doctrine/dbal": "< 3" + "php": "^7.2 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "13.0.0", - "phpstan/phpstan": "2.1.11", - "phpunit/phpunit": "^10.5.38 || 11.4.14" + "doctrine/coding-standard": "^12.0 || ^13.0", + "phpstan/phpstan": "^1.12 || ^2.0", + "phpstan/phpstan-phpunit": "^1.4 || ^2.0", + "phpstan/phpstan-strict-rules": "^1.6 || ^2.0", + "phpunit/phpunit": "^8.5 || ^12.2" }, - "type": "symfony-bundle", + "type": "library", "autoload": { "psr-4": { - "Doctrine\\Bundle\\FixturesBundle\\": "src" + "Doctrine\\Inflector\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -8564,27 +8433,43 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" }, { - "name": "Doctrine Project", - "homepage": "https://www.doctrine-project.org" + "name": "Roman Borschel", + "email": "roman@code-factory.org" }, { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" } ], - "description": "Symfony DoctrineFixturesBundle", - "homepage": "https://www.doctrine-project.org", + "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.", + "homepage": "https://www.doctrine-project.org/projects/inflector.html", "keywords": [ - "Fixture", - "persistence" + "inflection", + "inflector", + "lowercase", + "manipulation", + "php", + "plural", + "singular", + "strings", + "uppercase", + "words" ], "support": { - "issues": "https://github.com/doctrine/DoctrineFixturesBundle/issues", - "source": "https://github.com/doctrine/DoctrineFixturesBundle/tree/4.1.0" + "issues": "https://github.com/doctrine/inflector/issues", + "source": "https://github.com/doctrine/inflector/tree/2.1.0" }, "funding": [ { @@ -8596,11 +8481,11 @@ "type": "patreon" }, { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdoctrine-fixtures-bundle", + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector", "type": "tidelift" } ], - "time": "2025-03-26T10:56:26+00:00" + "time": "2025-08-10T19:31:58+00:00" }, { "name": "myclabs/deep-copy", @@ -8838,13 +8723,61 @@ }, "time": "2022-02-21T01:04:05+00:00" }, + { + "name": "phpstan/extension-installer", + "version": "1.4.3", + "source": { + "type": "git", + "url": "https://github.com/phpstan/extension-installer.git", + "reference": "85e90b3942d06b2326fba0403ec24fe912372936" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/85e90b3942d06b2326fba0403ec24fe912372936", + "reference": "85e90b3942d06b2326fba0403ec24fe912372936", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.0", + "php": "^7.2 || ^8.0", + "phpstan/phpstan": "^1.9.0 || ^2.0" + }, + "require-dev": { + "composer/composer": "^2.0", + "php-parallel-lint/php-parallel-lint": "^1.2.0", + "phpstan/phpstan-strict-rules": "^0.11 || ^0.12 || ^1.0" + }, + "type": "composer-plugin", + "extra": { + "class": "PHPStan\\ExtensionInstaller\\Plugin" + }, + "autoload": { + "psr-4": { + "PHPStan\\ExtensionInstaller\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Composer plugin for automatic installation of PHPStan extensions", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpstan/extension-installer/issues", + "source": "https://github.com/phpstan/extension-installer/tree/1.4.3" + }, + "time": "2024-09-04T20:21:43+00:00" + }, { "name": "phpstan/phpstan", - "version": "2.1.30", + "version": "2.1.31", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/a4a7f159927983dd4f7c8020ed227d80b7f39d7d", - "reference": "a4a7f159927983dd4f7c8020ed227d80b7f39d7d", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/ead89849d879fe203ce9292c6ef5e7e76f867b96", + "reference": "ead89849d879fe203ce9292c6ef5e7e76f867b96", "shasum": "" }, "require": { @@ -8889,20 +8822,20 @@ "type": "github" } ], - "time": "2025-10-02T16:07:52+00:00" + "time": "2025-10-10T14:14:11+00:00" }, { "name": "phpstan/phpstan-doctrine", - "version": "2.0.6", + "version": "2.0.10", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-doctrine.git", - "reference": "934f5734812341358fc41c44006b30fa00c785f0" + "reference": "5eaf37b87288474051469aee9f937fc9d862f330" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/934f5734812341358fc41c44006b30fa00c785f0", - "reference": "934f5734812341358fc41c44006b30fa00c785f0", + "url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/5eaf37b87288474051469aee9f937fc9d862f330", + "reference": "5eaf37b87288474051469aee9f937fc9d862f330", "shasum": "" }, "require": { @@ -8936,7 +8869,8 @@ "phpstan/phpstan-strict-rules": "^2.0", "phpunit/phpunit": "^9.6.20", "ramsey/uuid": "^4.2", - "symfony/cache": "^5.4" + "symfony/cache": "^5.4", + "symfony/uid": "^5.4 || ^6.4 || ^7.3" }, "type": "phpstan-extension", "extra": { @@ -8959,9 +8893,9 @@ "description": "Doctrine extensions for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-doctrine/issues", - "source": "https://github.com/phpstan/phpstan-doctrine/tree/2.0.6" + "source": "https://github.com/phpstan/phpstan-doctrine/tree/2.0.10" }, - "time": "2025-09-10T07:06:30+00:00" + "time": "2025-10-06T10:01:02+00:00" }, { "name": "phpstan/phpstan-symfony", @@ -10892,6 +10826,68 @@ ], "time": "2025-06-23T16:12:08+00:00" }, + { + "name": "symfony/stopwatch", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/stopwatch.git", + "reference": "5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd", + "reference": "5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/service-contracts": "^2.5|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Stopwatch\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a way to profile code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/stopwatch/tree/v7.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-02-24T10:49:57+00:00" + }, { "name": "symfony/web-profiler-bundle", "version": "v7.3.4", diff --git a/config/bundles.php b/config/bundles.php index 5b167b209..55d715efa 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -3,14 +3,11 @@ return [ Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true], Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true], - Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true], + Doctrine\Bundle\MongoDBBundle\DoctrineMongoDBBundle::class => ['all' => true], Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true], Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true], - DAMA\DoctrineTestBundle\DAMADoctrineTestBundle::class => ['test' => true], - Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true], - Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true], Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true], Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true], Symfony\UX\TwigComponent\TwigComponentBundle::class => ['all' => true], diff --git a/config/packages/dama_doctrine_test_bundle.yaml b/config/packages/dama_doctrine_test_bundle.yaml deleted file mode 100644 index 3482cbae1..000000000 --- a/config/packages/dama_doctrine_test_bundle.yaml +++ /dev/null @@ -1,5 +0,0 @@ -when@test: - dama_doctrine_test: - enable_static_connection: true - enable_static_meta_data_cache: true - enable_static_query_cache: true diff --git a/config/packages/doctrine.php b/config/packages/doctrine.php deleted file mode 100644 index d8e1af611..000000000 --- a/config/packages/doctrine.php +++ /dev/null @@ -1,11 +0,0 @@ -extension('doctrine', [ - 'orm' => [ - 'enable_native_lazy_objects' => \PHP_VERSION_ID >= 80400, - ], - ]); -}; diff --git a/config/packages/doctrine.yaml b/config/packages/doctrine.yaml deleted file mode 100644 index 3a220dec3..000000000 --- a/config/packages/doctrine.yaml +++ /dev/null @@ -1,56 +0,0 @@ -doctrine: - dbal: - url: '%env(resolve:DATABASE_URL)%' - - # IMPORTANT: You MUST configure your server version, - # either here or in the DATABASE_URL env var (see .env file) - #server_version: '16' - - profiling_collect_backtrace: '%kernel.debug%' - use_savepoints: true - - orm: - auto_generate_proxy_classes: true - report_fields_where_declared: true - validate_xml_mapping: true - naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware - identity_generation_preferences: - Doctrine\DBAL\Platforms\PostgreSQLPlatform: identity - - auto_mapping: true - mappings: - App: - type: attribute - is_bundle: false - dir: '%kernel.project_dir%/src/Entity' - prefix: 'App\Entity' - alias: App - - controller_resolver: - auto_mapping: false - -when@test: - doctrine: - dbal: - # "TEST_TOKEN" is typically set by ParaTest - dbname_suffix: '_test%env(default::TEST_TOKEN)%' - -when@prod: - doctrine: - orm: - auto_generate_proxy_classes: false - proxy_dir: '%kernel.build_dir%/doctrine/orm/Proxies' - query_cache_driver: - type: pool - pool: doctrine.system_cache_pool - result_cache_driver: - type: pool - pool: doctrine.result_cache_pool - - framework: - cache: - pools: - doctrine.result_cache_pool: - adapter: cache.app - doctrine.system_cache_pool: - adapter: cache.system diff --git a/config/packages/doctrine_migrations.yaml b/config/packages/doctrine_migrations.yaml deleted file mode 100644 index 29231d94b..000000000 --- a/config/packages/doctrine_migrations.yaml +++ /dev/null @@ -1,6 +0,0 @@ -doctrine_migrations: - migrations_paths: - # namespace is arbitrary but should be different from App\Migrations - # as migrations classes should NOT be autoloaded - 'DoctrineMigrations': '%kernel.project_dir%/migrations' - enable_profiler: false diff --git a/config/packages/doctrine_mongodb.yaml b/config/packages/doctrine_mongodb.yaml new file mode 100644 index 000000000..e0326566a --- /dev/null +++ b/config/packages/doctrine_mongodb.yaml @@ -0,0 +1,31 @@ +doctrine_mongodb: + auto_generate_proxy_classes: true + auto_generate_hydrator_classes: true + connections: + default: + server: '%env(resolve:MONGODB_URL)%' + options: {} + default_database: '%env(resolve:MONGODB_DB)%' + document_managers: + default: + auto_mapping: true + mappings: + App: + dir: '%kernel.project_dir%/src/Document' + prefix: 'App\Document' + +when@prod: + doctrine_mongodb: + auto_generate_proxy_classes: false + auto_generate_hydrator_classes: false + document_managers: + default: + metadata_cache_driver: + type: service + id: doctrine_mongodb.system_cache_pool + + framework: + cache: + pools: + doctrine_mongodb.system_cache_pool: + adapter: cache.system diff --git a/config/packages/framework.yaml b/config/packages/framework.yaml index 1cd58c200..62fda0c1b 100644 --- a/config/packages/framework.yaml +++ b/config/packages/framework.yaml @@ -1,13 +1,21 @@ # see https://symfony.com/doc/current/reference/configuration/framework.html framework: secret: '%env(APP_SECRET)%' + csrf_protection: true + annotations: false + http_method_override: false + handle_all_throwables: true # this defines the codes of the locales (languages) available in the application # https://symfony.com/doc/current/reference/configuration/framework.html#enabled-locales enabled_locales: ['ar', 'bg', 'bn', 'bs', 'ca', 'cs', 'de', 'en', 'es', 'eu', 'fr', 'hr', 'id', 'it', 'ja', 'lt', 'ne', 'nl', 'pl', 'pt_BR', 'ro', 'ru', 'sl', 'sq', 'sr_Cyrl', 'sr_Latn', 'tr', 'uk', 'vi', 'zh_CN'] - # Note that the session will be started ONLY if you read or write from it. - session: true + # Enables session support. Note that the session will ONLY be started if you read or write from it. + # Remove or comment this section to explicitly disable session support. + session: + handler_id: session.handler.mongodb + cookie_secure: auto + cookie_samesite: lax # When using the HTTP Cache, ESI allows to render page fragments separately # and with different cache configurations for each fragment @@ -23,3 +31,12 @@ when@test: test: true session: storage_factory_id: session.storage.factory.mock_file + +services: + session.handler.mongodb: + class: Symfony\Component\HttpFoundation\Session\Storage\Handler\MongoDbSessionHandler + arguments: + $mongo: '@doctrine_mongodb.odm.default_connection' + $options: + database: '%env(MONGODB_DB)%' + collection: 'sessions' diff --git a/config/packages/security.yaml b/config/packages/security.yaml index f923e3b64..2fec1453f 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -11,7 +11,7 @@ security: # To see the users at src/App/DataFixtures/ORM/LoadFixtures.php # To load users from somewhere else: https://symfony.com/doc/current/security/user_provider.html#creating-a-custom-user-provider database_users: - entity: { class: App\Entity\User, property: username } + mongodb: { class: App\Document\User, property: username } # https://symfony.com/doc/current/security.html#a-authentication-firewalls firewalls: diff --git a/config/packages/validator.yaml b/config/packages/validator.yaml index 033ca41bb..d52e4d619 100644 --- a/config/packages/validator.yaml +++ b/config/packages/validator.yaml @@ -6,7 +6,7 @@ framework: # Enables validator auto-mapping support. # For instance, basic validation constraints will be inferred from Doctrine's metadata. auto_mapping: - App\Entity\: [] + App\Document\: [] when@test: framework: diff --git a/config/services.yaml b/config/services.yaml index 70e38a69c..5114873ae 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -24,5 +24,13 @@ services: App\: resource: '../src/' + # Enable autowiring for MongoDB ODM Repositories + # This is incompatible with Doctrine ORM which also declare this alias + Doctrine\Persistence\ManagerRegistry: '@doctrine_mongodb' + + # Necessary to resolve the documents in controller arguments + Symfony\Bridge\Doctrine\ArgumentResolver\EntityValueResolver: + tags: ['controller.argument_value_resolver'] + # add more service definitions when explicit configuration is needed # please note that last definitions always *replace* previous ones diff --git a/data/database.sqlite b/data/database.sqlite deleted file mode 100644 index cbd2bf8b2..000000000 Binary files a/data/database.sqlite and /dev/null differ diff --git a/data/database_test.sqlite b/data/database_test.sqlite deleted file mode 100644 index 1bdf92e07..000000000 Binary files a/data/database_test.sqlite and /dev/null differ diff --git a/phpunit.dist.xml b/phpunit.dist.xml index c0155f869..6250eb0e9 100644 --- a/phpunit.dist.xml +++ b/phpunit.dist.xml @@ -42,7 +42,7 @@ - + diff --git a/src/Command/AddUserCommand.php b/src/Command/AddUserCommand.php index 129ee72a0..c052595f5 100644 --- a/src/Command/AddUserCommand.php +++ b/src/Command/AddUserCommand.php @@ -11,10 +11,10 @@ namespace App\Command; -use App\Entity\User; +use App\Document\User; use App\Repository\UserRepository; use App\Utils\Validator; -use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ODM\MongoDB\DocumentManager; use Symfony\Component\Console\Attribute\Argument; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Attribute\Option; @@ -58,7 +58,7 @@ final class AddUserCommand extends Command private SymfonyStyle $io; public function __construct( - private readonly EntityManagerInterface $entityManager, + private readonly DocumentManager $documentManager, private readonly UserPasswordHasherInterface $passwordHasher, private readonly Validator $validator, private readonly UserRepository $users, @@ -178,8 +178,8 @@ public function __invoke( $hashedPassword = $this->passwordHasher->hashPassword($user, $plainPassword); $user->setPassword($hashedPassword); - $this->entityManager->persist($user); - $this->entityManager->flush(); + $this->documentManager->persist($user); + $this->documentManager->flush(); $this->io->success(\sprintf('%s was successfully created: %s (%s)', $isAdmin ? 'Administrator user' : 'User', $user->getUsername(), $user->getEmail())); diff --git a/src/Command/DeleteUserCommand.php b/src/Command/DeleteUserCommand.php index 39d9d7c72..654b5c700 100644 --- a/src/Command/DeleteUserCommand.php +++ b/src/Command/DeleteUserCommand.php @@ -11,10 +11,10 @@ namespace App\Command; -use App\Entity\User; +use App\Document\User; use App\Repository\UserRepository; use App\Utils\Validator; -use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ODM\MongoDB\DocumentManager; use Psr\Log\LoggerInterface; use Symfony\Component\Console\Attribute\Argument; use Symfony\Component\Console\Attribute\AsCommand; @@ -58,7 +58,7 @@ final class DeleteUserCommand extends Command private SymfonyStyle $io; public function __construct( - private readonly EntityManagerInterface $entityManager, + private readonly DocumentManager $documentManager, private readonly Validator $validator, private readonly UserRepository $users, private readonly LoggerInterface $logger, @@ -114,13 +114,13 @@ public function __invoke(#[Argument('The username of an existing user')] string // See https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/working-with-objects.html#removing-entities $userId = $user->getId(); - $this->entityManager->remove($user); - $this->entityManager->flush(); + $this->documentManager->remove($user); + $this->documentManager->flush(); $userUsername = $user->getUsername(); $userEmail = $user->getEmail(); - $this->io->success(\sprintf('User "%s" (ID: %d, email: %s) was successfully deleted.', $userUsername, $userId, $userEmail)); + $this->io->success(\sprintf('User "%s" (ID: %s, email: %s) was successfully deleted.', $userUsername, $userId, $userEmail)); // Logging is helpful and important to keep a trace of what happened in the software runtime flow. // See https://symfony.com/doc/current/logging.html diff --git a/src/Command/ListUsersCommand.php b/src/Command/ListUsersCommand.php index cfecb44fa..fab614a7b 100644 --- a/src/Command/ListUsersCommand.php +++ b/src/Command/ListUsersCommand.php @@ -11,7 +11,7 @@ namespace App\Command; -use App\Entity\User; +use App\Document\User; use App\Repository\UserRepository; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Attribute\Option; diff --git a/src/Controller/Admin/BlogController.php b/src/Controller/Admin/BlogController.php index e9d7fc91e..8ae0300a5 100644 --- a/src/Controller/Admin/BlogController.php +++ b/src/Controller/Admin/BlogController.php @@ -11,12 +11,12 @@ namespace App\Controller\Admin; -use App\Entity\Post; -use App\Entity\User; +use App\Document\Post; +use App\Document\User; use App\Form\PostType; use App\Repository\PostRepository; use App\Security\PostVoter; -use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ODM\MongoDB\DocumentManager; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\SubmitButton; @@ -42,6 +42,8 @@ #[IsGranted(User::ROLE_ADMIN)] final class BlogController extends AbstractController { + private const MONGODB_OBJECTID = '[0-9a-f]{24}'; + /** * Lists all Post entities. * @@ -75,7 +77,7 @@ public function index( public function new( #[CurrentUser] User $user, Request $request, - EntityManagerInterface $entityManager, + DocumentManager $documentManager, ): Response { $post = new Post(); $post->setAuthor($user); @@ -91,8 +93,8 @@ public function new( // throws an exception if the form has not been submitted. // See https://symfony.com/doc/current/forms.html#processing-forms if ($form->isSubmitted() && $form->isValid()) { - $entityManager->persist($post); - $entityManager->flush(); + $documentManager->persist($post); + $documentManager->flush(); // Flash messages are used to notify the user about the result of the // actions. They are deleted automatically from the session as soon @@ -119,7 +121,7 @@ public function new( /** * Finds and displays a Post entity. */ - #[Route('/{id:post}', name: 'admin_post_show', requirements: ['id' => Requirement::POSITIVE_INT], methods: ['GET'])] + #[Route('/{id}', name: 'admin_post_show', requirements: ['id' => self::MONGODB_OBJECTID], methods: ['GET'])] public function show(Post $post): Response { // This security check can also be performed @@ -134,15 +136,15 @@ public function show(Post $post): Response /** * Displays a form to edit an existing Post entity. */ - #[Route('/{id:post}/edit', name: 'admin_post_edit', requirements: ['id' => Requirement::POSITIVE_INT], methods: ['GET', 'POST'])] + #[Route('/{id}/edit', name: 'admin_post_edit', requirements: ['id' => self::MONGODB_OBJECTID], methods: ['GET', 'POST'])] #[IsGranted('edit', subject: 'post', message: 'Posts can only be edited by their authors.')] - public function edit(Request $request, Post $post, EntityManagerInterface $entityManager): Response + public function edit(Request $request, Post $post, DocumentManager $documentManager): Response { $form = $this->createForm(PostType::class, $post); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - $entityManager->flush(); + $documentManager->flush(); $this->addFlash('success', 'post.updated_successfully'); return $this->redirectToRoute('admin_post_edit', ['id' => $post->getId()], Response::HTTP_SEE_OTHER); @@ -157,9 +159,9 @@ public function edit(Request $request, Post $post, EntityManagerInterface $entit /** * Deletes a Post entity. */ - #[Route('/{id:post}/delete', name: 'admin_post_delete', requirements: ['id' => Requirement::POSITIVE_INT], methods: ['POST'])] + #[Route('/{id}/delete', name: 'admin_post_delete', requirements: ['id' => self::MONGODB_OBJECTID], methods: ['POST'])] #[IsGranted('delete', subject: 'post')] - public function delete(Request $request, Post $post, EntityManagerInterface $entityManager): Response + public function delete(Request $request, Post $post, DocumentManager $documentManager): Response { /** @var string|null $token */ $token = $request->getPayload()->get('token'); @@ -173,8 +175,8 @@ public function delete(Request $request, Post $post, EntityManagerInterface $ent // because foreign key support is not enabled by default in SQLite $post->getTags()->clear(); - $entityManager->remove($post); - $entityManager->flush(); + $documentManager->remove($post); + $documentManager->flush(); $this->addFlash('success', 'post.deleted_successfully'); diff --git a/src/Controller/BlogController.php b/src/Controller/BlogController.php index 6263a5f8a..7e8090cdd 100644 --- a/src/Controller/BlogController.php +++ b/src/Controller/BlogController.php @@ -11,14 +11,14 @@ namespace App\Controller; -use App\Entity\Comment; -use App\Entity\Post; -use App\Entity\User; +use App\Document\Comment; +use App\Document\Post; +use App\Document\User; use App\Event\CommentCreatedEvent; use App\Form\CommentType; use App\Repository\PostRepository; use App\Repository\TagRepository; -use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ODM\MongoDB\DocumentManager; use Symfony\Bridge\Doctrine\Attribute\MapEntity; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\EventDispatcher\EventDispatcherInterface; @@ -49,13 +49,9 @@ final class BlogController extends AbstractController #[Route('/rss.xml', name: 'blog_rss', defaults: ['page' => '1', '_format' => 'xml'], methods: ['GET'])] #[Route('/page/{page}', name: 'blog_index_paginated', defaults: ['_format' => 'html'], requirements: ['page' => Requirement::POSITIVE_INT], methods: ['GET'])] #[Cache(smaxage: 10)] - public function index(Request $request, int $page, string $_format, PostRepository $posts, TagRepository $tags): Response + public function index(Request $request, int $page, string $_format, PostRepository $posts): Response { - $tag = null; - - if ($request->query->has('tag')) { - $tag = $tags->findOneBy(['name' => $request->query->get('tag')]); - } + $tag = $request->query->getString('tag'); $latestPosts = $posts->findLatest($page, $tag); @@ -64,7 +60,7 @@ public function index(Request $request, int $page, string $_format, PostReposito // See https://symfony.com/doc/current/templates.html#template-naming return $this->render('blog/index.'.$_format.'.twig', [ 'paginator' => $latestPosts, - 'tagName' => $tag?->getName(), + 'tagName' => $tag, ]); } @@ -110,7 +106,7 @@ public function commentNew( Request $request, #[MapEntity(mapping: ['postSlug' => 'slug'])] Post $post, EventDispatcherInterface $eventDispatcher, - EntityManagerInterface $entityManager, + DocumentManager $documentManager, ): Response { $comment = new Comment(); $comment->setAuthor($user); @@ -120,8 +116,8 @@ public function commentNew( $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - $entityManager->persist($comment); - $entityManager->flush(); + $documentManager->persist($comment); + $documentManager->flush(); // When an event is dispatched, Symfony notifies it to all the listeners // and subscribers registered to it. Listeners can modify the information diff --git a/src/Controller/SecurityController.php b/src/Controller/SecurityController.php index 06104fd66..ea2fae6b4 100644 --- a/src/Controller/SecurityController.php +++ b/src/Controller/SecurityController.php @@ -11,7 +11,7 @@ namespace App\Controller; -use App\Entity\User; +use App\Document\User; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; diff --git a/src/Controller/UserController.php b/src/Controller/UserController.php index d73acdd59..f9701df43 100644 --- a/src/Controller/UserController.php +++ b/src/Controller/UserController.php @@ -11,10 +11,10 @@ namespace App\Controller; -use App\Entity\User; +use App\Document\User; use App\Form\ChangePasswordType; use App\Form\UserType; -use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ODM\MongoDB\DocumentManager; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\HttpFoundation\Request; @@ -38,13 +38,13 @@ final class UserController extends AbstractController public function edit( #[CurrentUser] User $user, Request $request, - EntityManagerInterface $entityManager, + DocumentManager $documentManager, ): Response { $form = $this->createForm(UserType::class, $user); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - $entityManager->flush(); + $documentManager->flush(); $this->addFlash('success', 'user.updated_successfully'); @@ -61,14 +61,14 @@ public function edit( public function changePassword( #[CurrentUser] User $user, Request $request, - EntityManagerInterface $entityManager, + DocumentManager $documentManager, Security $security, ): Response { $form = $this->createForm(ChangePasswordType::class, $user); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - $entityManager->flush(); + $documentManager->flush(); // The logout method applies an automatic protection against CSRF attacks; // it's explicitly disabled here because the form already has a CSRF token validated. diff --git a/src/DataFixtures/AppFixtures.php b/src/DataFixtures/AppFixtures.php index 4acc8b1ed..8627fed7b 100644 --- a/src/DataFixtures/AppFixtures.php +++ b/src/DataFixtures/AppFixtures.php @@ -11,11 +11,12 @@ namespace App\DataFixtures; -use App\Entity\Comment; -use App\Entity\Post; -use App\Entity\Tag; -use App\Entity\User; -use Doctrine\Bundle\FixturesBundle\Fixture; +use App\Document\Comment; +use App\Document\Post; +use App\Document\Tag; +use App\Document\User; +use Doctrine\Bundle\MongoDBBundle\Fixture\Fixture; +use Doctrine\ODM\MongoDB\DocumentManager; use Doctrine\Persistence\ObjectManager; use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; use Symfony\Component\String\AbstractUnicodeString; @@ -69,10 +70,12 @@ private function loadTags(ObjectManager $manager): void $manager->flush(); } - private function loadPosts(ObjectManager $manager): void + private function loadPosts(DocumentManager $manager): void { - foreach ($this->getPostData() as [$title, $slug, $summary, $content, $publishedAt, $author, $tags]) { + foreach ($this->getPostData() as $i => [$title, $slug, $summary, $content, $publishedAt, $author, $tags]) { $post = new Post(); + // Force the ID to have a predictable value to simplify tests + $manager->getClassMetadata(Post::class)->setFieldValue($post, 'id', sprintf('68f14cc10152bda8580dd7%02d', $i)); $post->setTitle($title); $post->setSlug($slug); $post->setSummary($summary); @@ -88,6 +91,7 @@ private function loadPosts(ObjectManager $manager): void $comment->setPublishedAt(new \DateTimeImmutable('now + '.$i.'seconds')); $post->addComment($comment); + $manager->persist($comment); } $manager->persist($post); diff --git a/migrations/.gitignore b/src/Document/.gitignore similarity index 100% rename from migrations/.gitignore rename to src/Document/.gitignore diff --git a/src/Entity/Comment.php b/src/Document/Comment.php similarity index 75% rename from src/Entity/Comment.php rename to src/Document/Comment.php index 29335751b..74b1abf1c 100644 --- a/src/Entity/Comment.php +++ b/src/Document/Comment.php @@ -9,45 +9,37 @@ * file that was distributed with this source code. */ -namespace App\Entity; +namespace App\Document; -use Doctrine\DBAL\Types\Types; -use Doctrine\ORM\Mapping as ORM; +use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM; +use Doctrine\ODM\MongoDB\Types\Type; use Symfony\Component\Validator\Constraints as Assert; use function Symfony\Component\String\u; /** - * Defines the properties of the Comment entity to represent the blog comments. + * Defines the properties of the Comment document to represent the blog comments. * * See https://symfony.com/doc/current/doctrine.html#creating-an-entity-class * * @author Ryan Weaver * @author Javier Eguiluz */ -#[ORM\Entity] -#[ORM\Table(name: 'symfony_demo_comment')] +#[ODM\Document] class Comment { - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column(type: Types::INTEGER)] - private ?int $id = null; + #[ODM\Id] + private ?string $id = null; - #[ORM\ManyToOne(targetEntity: Post::class, inversedBy: 'comments')] - #[ORM\JoinColumn(nullable: false)] - private ?Post $post = null; - - #[ORM\Column(type: Types::TEXT)] + #[ODM\Field(type: Type::STRING)] #[Assert\NotBlank(message: 'comment.blank')] #[Assert\Length(min: 5, max: 10000, minMessage: 'comment.too_short', maxMessage: 'comment.too_long')] private ?string $content = null; - #[ORM\Column] + #[ODM\Field(type: Type::DATE_IMMUTABLE)] private \DateTimeImmutable $publishedAt; - #[ORM\ManyToOne(targetEntity: User::class)] - #[ORM\JoinColumn(nullable: false)] + #[ODM\ReferenceOne(nullable: false, targetDocument: User::class)] private ?User $author = null; public function __construct() @@ -63,7 +55,7 @@ public function isLegitComment(): bool return !$containsInvalidCharacters; } - public function getId(): ?int + public function getId(): ?string { return $this->id; } diff --git a/src/Entity/Post.php b/src/Document/Post.php similarity index 74% rename from src/Entity/Post.php rename to src/Document/Post.php index dbb43127d..3e1405a8f 100644 --- a/src/Entity/Post.php +++ b/src/Document/Post.php @@ -9,18 +9,17 @@ * file that was distributed with this source code. */ -namespace App\Entity; +namespace App\Document; use App\Repository\PostRepository; +use Doctrine\Bundle\MongoDBBundle\Validator\Constraints\Unique; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; -use Doctrine\DBAL\Types\Types; -use Doctrine\ORM\Mapping as ORM; -use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM; use Symfony\Component\Validator\Constraints as Assert; /** - * Defines the properties of the Post entity to represent the blog posts. + * Defines the properties of the Post document to represent the blog posts. * * See https://symfony.com/doc/current/doctrine.html#creating-an-entity-class * @@ -28,54 +27,51 @@ * @author Javier Eguiluz * @author Yonel Ceruto */ -#[ORM\Entity(repositoryClass: PostRepository::class)] -#[ORM\Table(name: 'symfony_demo_post')] -#[UniqueEntity(fields: ['slug'], errorPath: 'title', message: 'post.slug_unique')] +#[ODM\Document(repositoryClass: PostRepository::class)] +#[ODM\UniqueIndex(keys: ['slug' => 1], options: ['unique' => true])] +#[ODM\Index(['order' => 'desc', 'tags.name' => 'asc'])] +#[Unique(fields: ['slug'], message: 'post.slug_unique', errorPath: 'title')] class Post { - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column(type: Types::INTEGER)] - private ?int $id = null; + #[ODM\Id] + private ?string $id = null; - #[ORM\Column(type: Types::STRING)] + #[ODM\Field] #[Assert\NotBlank] private ?string $title = null; - #[ORM\Column(type: Types::STRING)] + #[ODM\Field] private ?string $slug = null; - #[ORM\Column(type: Types::STRING)] + #[ODM\Field] #[Assert\NotBlank(message: 'post.blank_summary')] #[Assert\Length(max: 255)] private ?string $summary = null; - #[ORM\Column(type: Types::TEXT)] + #[ODM\Field] #[Assert\NotBlank(message: 'post.blank_content')] #[Assert\Length(min: 10, minMessage: 'post.too_short_content')] private ?string $content = null; - #[ORM\Column] + #[ODM\Field] private \DateTimeImmutable $publishedAt; - #[ORM\ManyToOne(targetEntity: User::class)] - #[ORM\JoinColumn(nullable: false)] + #[ODM\ReferenceOne(nullable: false, targetDocument: User::class)] private ?User $author = null; /** * @var Collection */ - #[ORM\OneToMany(targetEntity: Comment::class, mappedBy: 'post', orphanRemoval: true, cascade: ['persist'])] - #[ORM\OrderBy(['publishedAt' => 'DESC'])] + #[ODM\ReferenceMany(targetDocument: Comment::class)] + #[Assert\Type(type: Collection::class, message: 'post.invalid_tags')] private Collection $comments; /** * @var Collection */ - #[ORM\ManyToMany(targetEntity: Tag::class, cascade: ['persist'])] - #[ORM\JoinTable(name: 'symfony_demo_post_tag')] - #[ORM\OrderBy(['name' => 'ASC'])] + #[ODM\EmbedMany(targetDocument: Tag::class)] #[Assert\Count(max: 4, maxMessage: 'post.too_many_tags')] + #[Assert\Type(type: Collection::class, message: 'post.invalid_tags')] private Collection $tags; public function __construct() @@ -85,7 +81,7 @@ public function __construct() $this->tags = new ArrayCollection(); } - public function getId(): ?int + public function getId(): ?string { return $this->id; } @@ -120,13 +116,16 @@ public function setContent(?string $content): void $this->content = $content; } - public function getPublishedAt(): \DateTimeImmutable + public function getPublishedAt(): \DateTimeInterface { return $this->publishedAt; } - public function setPublishedAt(\DateTimeImmutable $publishedAt): void + public function setPublishedAt(\DateTimeInterface $publishedAt): void { + if ($publishedAt instanceof \DateTime) { + $publishedAt = \DateTimeImmutable::createFromMutable($publishedAt); + } $this->publishedAt = $publishedAt; } diff --git a/src/Entity/Tag.php b/src/Document/Tag.php similarity index 61% rename from src/Entity/Tag.php rename to src/Document/Tag.php index 0979290f4..24a1731b1 100644 --- a/src/Entity/Tag.php +++ b/src/Document/Tag.php @@ -9,28 +9,20 @@ * file that was distributed with this source code. */ -namespace App\Entity; - -use Doctrine\DBAL\Types\Types; -use Doctrine\ORM\Mapping as ORM; +namespace App\Document; +use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM; +use Doctrine\ODM\MongoDB\Types\Type; /** - * Defines the properties of the Tag entity to represent the post tags. - * - * See https://symfony.com/doc/current/doctrine.html#creating-an-entity-class - * - * @author Yonel Ceruto + * Defines the properties of the Tag document to represent the post tags. */ -#[ORM\Entity] -#[ORM\Table(name: 'symfony_demo_tag')] +#[ODM\EmbeddedDocument] class Tag implements \JsonSerializable { - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column(type: Types::INTEGER)] - private ?int $id = null; - - #[ORM\Column(type: Types::STRING, unique: true)] + #[ODM\Field(type: Type::STRING)] + // With embedded documents, we don't need the unique index because the data + // is duplicated in each document + //#[ODM\UniqueIndex(keys: ['name' => 'asc'], options: ['unique' => true])] private readonly string $name; public function __construct(string $name) @@ -38,11 +30,6 @@ public function __construct(string $name) $this->name = $name; } - public function getId(): ?int - { - return $this->id; - } - public function getName(): string { return $this->name; diff --git a/src/Entity/User.php b/src/Document/User.php similarity index 84% rename from src/Entity/User.php rename to src/Document/User.php index 1253764f2..68d9ba8bd 100644 --- a/src/Entity/User.php +++ b/src/Document/User.php @@ -9,25 +9,24 @@ * file that was distributed with this source code. */ -namespace App\Entity; +namespace App\Document; use App\Repository\UserRepository; -use Doctrine\DBAL\Types\Types; -use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Validator\Constraints as Assert; +use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM; +use Doctrine\ODM\MongoDB\Types\Type; /** - * Defines the properties of the User entity to represent the application users. + * Defines the properties of the User document to represent the application users. * * See https://symfony.com/doc/current/doctrine.html#creating-an-entity-class * * @author Ryan Weaver * @author Javier Eguiluz */ -#[ORM\Entity(repositoryClass: UserRepository::class)] -#[ORM\Table(name: 'symfony_demo_user')] +#[ODM\Document(repositoryClass: UserRepository::class)] class User implements UserInterface, PasswordAuthenticatedUserInterface { // We can use constants for roles to find usages all over the application rather @@ -36,34 +35,34 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface final public const ROLE_USER = 'ROLE_USER'; final public const ROLE_ADMIN = 'ROLE_ADMIN'; - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column(type: Types::INTEGER)] - private ?int $id = null; + #[ODM\Id] + private ?string $id = null; - #[ORM\Column(type: Types::STRING)] + #[ODM\Field(type: Type::STRING)] #[Assert\NotBlank] private ?string $fullName = null; - #[ORM\Column(type: Types::STRING, unique: true)] + #[ODM\Field(type: Type::STRING)] + #[ODM\UniqueIndex] #[Assert\NotBlank] #[Assert\Length(min: 2, max: 50)] private ?string $username = null; - #[ORM\Column(type: Types::STRING, unique: true)] + #[ODM\Field(type: Type::STRING)] + #[ODM\UniqueIndex] #[Assert\Email] private ?string $email = null; - #[ORM\Column(type: Types::STRING)] + #[ODM\Field(type: Type::STRING)] private ?string $password = null; /** * @var string[] */ - #[ORM\Column(type: Types::JSON)] + #[ODM\Field(type: Type::COLLECTION, strategy: 'set')] private array $roles = []; - public function getId(): ?int + public function getId(): ?string { return $this->id; } diff --git a/src/Event/CommentCreatedEvent.php b/src/Event/CommentCreatedEvent.php index 34f0924b1..933648ebc 100644 --- a/src/Event/CommentCreatedEvent.php +++ b/src/Event/CommentCreatedEvent.php @@ -11,7 +11,7 @@ namespace App\Event; -use App\Entity\Comment; +use App\Document\Comment; use Symfony\Contracts\EventDispatcher\Event; final class CommentCreatedEvent extends Event diff --git a/src/EventSubscriber/CheckRequirementsSubscriber.php b/src/EventSubscriber/CheckRequirementsSubscriber.php deleted file mode 100644 index 52276079a..000000000 --- a/src/EventSubscriber/CheckRequirementsSubscriber.php +++ /dev/null @@ -1,100 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace App\EventSubscriber; - -use Doctrine\DBAL\Exception\DriverException; -use Doctrine\DBAL\Platforms\SQLitePlatform; -use Doctrine\ORM\EntityManagerInterface; -use Symfony\Component\Console\ConsoleEvents; -use Symfony\Component\Console\Event\ConsoleErrorEvent; -use Symfony\Component\Console\Style\SymfonyStyle; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\HttpKernel\Event\ExceptionEvent; -use Symfony\Component\HttpKernel\KernelEvents; - -/** - * This application uses by default an SQLite database to store its information. - * That's why the 'sqlite3' extension must be enabled in PHP. This event - * subscriber listens to console events and in case of an exception caused by - * a disabled 'sqlite3' extension, it displays a meaningful error message. - * - * @author Javier Eguiluz - */ -final readonly class CheckRequirementsSubscriber implements EventSubscriberInterface -{ - public function __construct( - private EntityManagerInterface $entityManager, - ) { - } - - // Event Subscribers must define this method to declare the events they - // listen to. You can listen to several events, execute more than one method - // for each event and set the priority of each event too. - // See https://symfony.com/doc/current/event_dispatcher.html#creating-an-event-subscriber - public static function getSubscribedEvents(): array - { - return [ - // Errors are one of the events defined by the Console. See the - // rest here: https://symfony.com/doc/current/components/console/events.html - ConsoleEvents::ERROR => 'handleConsoleError', - // See: https://symfony.com/doc/current/components/http_kernel.html#component-http-kernel-event-table - KernelEvents::EXCEPTION => 'handleKernelException', - ]; - } - - /** - * This method checks if there has been an error in a command related to - * the database and then, it checks if the 'sqlite3' PHP extension is enabled - * or not to display a better error message. - */ - public function handleConsoleError(ConsoleErrorEvent $event): void - { - $commandNames = ['doctrine:fixtures:load', 'doctrine:database:create', 'doctrine:schema:create', 'doctrine:database:drop']; - - if ($event->getCommand() && \in_array($event->getCommand()->getName(), $commandNames, true)) { - if ($this->isSQLitePlatform() && !\extension_loaded('sqlite3')) { - $io = new SymfonyStyle($event->getInput(), $event->getOutput()); - $io->error('This command requires to have the "sqlite3" PHP extension enabled because, by default, the Symfony Demo application uses SQLite to store its information.'); - } - } - } - - /** - * This method checks if the triggered exception is related to the database - * and then, it checks if the required 'sqlite3' PHP extension is enabled. - */ - public function handleKernelException(ExceptionEvent $event): void - { - $exception = $event->getThrowable(); - // Since any exception thrown during a Twig template rendering is wrapped - // in a Twig_Error_Runtime, we must get the original exception. - $previousException = $exception->getPrevious(); - - // Driver exception may happen in controller or in twig template rendering - $isDriverException = ($exception instanceof DriverException || $previousException instanceof DriverException); - - // Check if SQLite is enabled - if ($isDriverException && $this->isSQLitePlatform() && !\extension_loaded('sqlite3')) { - $event->setThrowable(new \Exception('PHP extension "sqlite3" must be enabled because, by default, the Symfony Demo application uses SQLite to store its information.')); - } - } - - /** - * Checks if the application is using SQLite as its database. - */ - private function isSQLitePlatform(): bool - { - $databasePlatform = $this->entityManager->getConnection()->getDatabasePlatform(); - - return $databasePlatform instanceof SQLitePlatform; - } -} diff --git a/src/EventSubscriber/CommentNotificationSubscriber.php b/src/EventSubscriber/CommentNotificationSubscriber.php index 32c81b636..33f78eb6f 100644 --- a/src/EventSubscriber/CommentNotificationSubscriber.php +++ b/src/EventSubscriber/CommentNotificationSubscriber.php @@ -11,8 +11,8 @@ namespace App\EventSubscriber; -use App\Entity\Post; -use App\Entity\User; +use App\Document\Post; +use App\Document\User; use App\Event\CommentCreatedEvent; use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\EventDispatcher\EventSubscriberInterface; diff --git a/src/Form/ChangePasswordType.php b/src/Form/ChangePasswordType.php index f3eb36ed8..95889d626 100644 --- a/src/Form/ChangePasswordType.php +++ b/src/Form/ChangePasswordType.php @@ -11,7 +11,7 @@ namespace App\Form; -use App\Entity\User; +use App\Document\User; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\PasswordType; use Symfony\Component\Form\Extension\Core\Type\RepeatedType; diff --git a/src/Form/CommentType.php b/src/Form/CommentType.php index 72e61154f..9b37a6e06 100644 --- a/src/Form/CommentType.php +++ b/src/Form/CommentType.php @@ -11,7 +11,7 @@ namespace App\Form; -use App\Entity\Comment; +use App\Document\Comment; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\FormBuilderInterface; diff --git a/src/Form/DataTransformer/TagArrayToStringTransformer.php b/src/Form/DataTransformer/TagArrayToStringTransformer.php index 6258e59e1..3622fd4e0 100644 --- a/src/Form/DataTransformer/TagArrayToStringTransformer.php +++ b/src/Form/DataTransformer/TagArrayToStringTransformer.php @@ -11,8 +11,7 @@ namespace App\Form\DataTransformer; -use App\Entity\Tag; -use App\Repository\TagRepository; +use App\Document\Tag; use Symfony\Component\Form\DataTransformerInterface; use function Symfony\Component\String\u; @@ -30,50 +29,33 @@ */ final readonly class TagArrayToStringTransformer implements DataTransformerInterface { - public function __construct( - private TagRepository $tags, - ) { - } - - public function transform($tags): string + public function transform($value): string { // The value received is an array of Tag objects generated with // Symfony\Bridge\Doctrine\Form\DataTransformer\CollectionToArrayTransformer::transform() // The value returned is a string that concatenates the string representation of those objects - return implode(',', $tags); + return implode(',', $value); } /** - * @phpstan-param string|null $string + * @phpstan-param string|null $value * - * @phpstan-return array + * @return Tag[] */ - public function reverseTransform($string): array + public function reverseTransform($value): array { - if (null === $string || u($string)->isEmpty()) { + if (null === $value || u($value)->isEmpty()) { return []; } - $names = array_filter(array_unique($this->trim(u($string)->split(',')))); - - // Get the current tags and find the new ones that should be created. - /** @var Tag[] $tags */ - $tags = $this->tags->findBy([ - 'name' => $names, - ]); - - $newNames = array_diff($names, $tags); - - foreach ($newNames as $name) { - $tags[] = new Tag($name); + $names = array_filter(array_unique(u($value)->split(','))); - // There's no need to persist these new tags because Doctrine does that automatically - // thanks to the cascade={"persist"} option in the App\Entity\Post::$tags property. + $tags = []; + foreach ($names as $name) { + $tags[] = new Tag(u($name)->trim()); } - // Return an array of tags to transform them back into a Doctrine Collection. - // See Symfony\Bridge\Doctrine\Form\DataTransformer\CollectionToArrayTransformer::reverseTransform() return $tags; } diff --git a/src/Form/PostType.php b/src/Form/PostType.php index 8411a07a5..9f8123701 100644 --- a/src/Form/PostType.php +++ b/src/Form/PostType.php @@ -11,7 +11,7 @@ namespace App\Form; -use App\Entity\Post; +use App\Document\Post; use App\Form\Type\DateTimePickerType; use App\Form\Type\TagsInputType; use Symfony\Component\Form\AbstractType; diff --git a/src/Form/Type/TagsInputType.php b/src/Form/Type/TagsInputType.php index 60ca16570..22ece3711 100644 --- a/src/Form/Type/TagsInputType.php +++ b/src/Form/Type/TagsInputType.php @@ -12,7 +12,7 @@ namespace App\Form\Type; use App\Form\DataTransformer\TagArrayToStringTransformer; -use App\Repository\TagRepository; +use App\Repository\PostRepository; use Symfony\Bridge\Doctrine\Form\DataTransformer\CollectionToArrayTransformer; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\TextType; @@ -31,7 +31,7 @@ final class TagsInputType extends AbstractType { public function __construct( - private readonly TagRepository $tags, + private readonly PostRepository $postRepository ) { } @@ -43,13 +43,13 @@ public function buildForm(FormBuilderInterface $builder, array $options): void // but here we're doing the transformation in two steps (Collection <-> array <-> string) // and reuse the existing CollectionToArrayTransformer. ->addModelTransformer(new CollectionToArrayTransformer(), true) - ->addModelTransformer(new TagArrayToStringTransformer($this->tags), true) + ->addModelTransformer(new TagArrayToStringTransformer(), true) ; } public function buildView(FormView $view, FormInterface $form, array $options): void { - $view->vars['tags'] = $this->tags->findAll(); + $view->vars['tags'] = $this->postRepository->findAllTags(); } public function getParent(): string diff --git a/src/Form/UserType.php b/src/Form/UserType.php index 51f672f66..cc9ecc9d6 100644 --- a/src/Form/UserType.php +++ b/src/Form/UserType.php @@ -11,7 +11,7 @@ namespace App\Form; -use App\Entity\User; +use App\Document\User; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\EmailType; use Symfony\Component\Form\Extension\Core\Type\TextType; diff --git a/src/Pagination/Paginator.php b/src/Pagination/Paginator.php index af0a57a70..fbe48df1a 100644 --- a/src/Pagination/Paginator.php +++ b/src/Pagination/Paginator.php @@ -11,9 +11,9 @@ namespace App\Pagination; -use Doctrine\ORM\QueryBuilder as DoctrineQueryBuilder; -use Doctrine\ORM\Tools\Pagination\CountWalker; -use Doctrine\ORM\Tools\Pagination\Paginator as DoctrinePaginator; +use Doctrine\ODM\MongoDB\DocumentManager; +use Doctrine\ODM\MongoDB\Query\Builder as DoctrineQueryBuilder; +use Doctrine\ODM\MongoDB\Repository\DocumentRepository; /** * @author Javier Eguiluz @@ -47,29 +47,17 @@ public function paginate(int $page = 1): self $this->currentPage = max(1, $page); $firstResult = ($this->currentPage - 1) * $this->pageSize; - $query = $this->queryBuilder - ->setFirstResult($firstResult) - ->setMaxResults($this->pageSize) + $countQuery = (clone $this->queryBuilder) + ->count() ->getQuery(); - /** @var array $joinDqlParts */ - $joinDqlParts = $this->queryBuilder->getDQLPart('join'); - - if (0 === \count($joinDqlParts)) { - $query->setHint(CountWalker::HINT_DISTINCT, false); - } - - /** @var DoctrinePaginator $paginator */ - $paginator = new DoctrinePaginator($query, true); - - /** @var array $havingDqlParts */ - $havingDqlParts = $this->queryBuilder->getDQLPart('having'); - - $useOutputWalkers = \count($havingDqlParts ?: []) > 0; - $paginator->setUseOutputWalkers($useOutputWalkers); + $query = $this->queryBuilder + ->skip($firstResult) + ->limit($this->pageSize) + ->getQuery(); - $this->results = $paginator->getIterator(); - $this->numResults = $paginator->count(); + $this->results = $query->execute(); + $this->numResults = $countQuery->execute(); return $this; } diff --git a/src/Repository/PostRepository.php b/src/Repository/PostRepository.php index 0f949e097..081c65632 100644 --- a/src/Repository/PostRepository.php +++ b/src/Repository/PostRepository.php @@ -11,10 +11,10 @@ namespace App\Repository; -use App\Entity\Post; -use App\Entity\Tag; +use App\Document\Post; +use App\Document\Tag; use App\Pagination\Paginator; -use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; +use Doctrine\Bundle\MongoDBBundle\Repository\ServiceDocumentRepository; use Doctrine\Persistence\ManagerRegistry; use function Symfony\Component\String\u; @@ -25,35 +25,25 @@ * * See https://symfony.com/doc/current/doctrine.html#querying-for-objects-the-repository * - * @author Ryan Weaver - * @author Javier Eguiluz - * @author Yonel Ceruto - * * @method Post|null findOneByTitle(string $postTitle) * - * @template-extends ServiceEntityRepository + * @template-extends ServiceDocumentRepository */ -class PostRepository extends ServiceEntityRepository +class PostRepository extends ServiceDocumentRepository { public function __construct(ManagerRegistry $registry) { parent::__construct($registry, Post::class); } - public function findLatest(int $page = 1, ?Tag $tag = null): Paginator + public function findLatest(int $page = 1, ?string $tag = null): Paginator { - $qb = $this->createQueryBuilder('p') - ->addSelect('a', 't') - ->innerJoin('p.author', 'a') - ->leftJoin('p.tags', 't') - ->where('p.publishedAt <= :now') - ->orderBy('p.publishedAt', 'DESC') - ->setParameter('now', new \DateTimeImmutable()) - ; + $qb = $this->createQueryBuilder() + ->field('publishedAt')->lte(new \DateTimeImmutable()) // $$NOW is a MongoDB variable that returns the current date + ->sort('publishedAt', 'DESC'); - if (null !== $tag) { - $qb->andWhere(':tag MEMBER OF p.tags') - ->setParameter('tag', $tag); + if ($tag) { + $qb->field('tags.name')->equals($tag); } return (new Paginator($qb))->paginate($page); @@ -64,28 +54,16 @@ public function findLatest(int $page = 1, ?Tag $tag = null): Paginator */ public function findBySearchQuery(string $query, int $limit = Paginator::PAGE_SIZE): array { - $searchTerms = $this->extractSearchTerms($query); - - if (0 === \count($searchTerms)) { + if (!$query) { return []; } - $queryBuilder = $this->createQueryBuilder('p'); - - foreach ($searchTerms as $key => $term) { - $queryBuilder - ->orWhere('p.title LIKE :t_'.$key) - ->setParameter('t_'.$key, '%'.$term.'%') - ; - } - /** @var Post[] $result */ - $result = $queryBuilder - ->orderBy('p.publishedAt', 'DESC') - ->setMaxResults($limit) - ->getQuery() - ->getResult() - ; + $result = $this->findBy( + ['$text' => ['$search' => $query]], + ['publishedAt' => -1], + $limit + ); return $result; } @@ -95,13 +73,16 @@ public function findBySearchQuery(string $query, int $limit = Paginator::PAGE_SI * * @return string[] */ - private function extractSearchTerms(string $searchQuery): array + public function findAllTags(): array { - $terms = array_unique(u($searchQuery)->replaceMatches('/[[:space:]]+/', ' ')->trim()->split(' ')); - - // ignore the search terms that are too short - return array_filter($terms, static function ($term) { - return 2 <= $term->length(); - }); + $result = $this->createAggregationBuilder() + ->unwind('$tags') + ->sortByCount('$tags.name') + ->project()->includeFields(['_id']) + ->getAggregation() + ->getIterator() + ->toArray(); + + return array_column($result, '_id'); } } diff --git a/src/Repository/TagRepository.php b/src/Repository/TagRepository.php deleted file mode 100644 index 976a1bdcc..000000000 --- a/src/Repository/TagRepository.php +++ /dev/null @@ -1,35 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace App\Repository; - -use App\Entity\Tag; -use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; -use Doctrine\Persistence\ManagerRegistry; - -/** - * This custom Doctrine repository is empty because so far we don't need any custom - * method to query for application user information. But it's always a good practice - * to define a custom repository that will be used when the application grows. - * - * See https://symfony.com/doc/current/doctrine.html#querying-for-objects-the-repository - * - * @author Yonel Ceruto - * - * @template-extends ServiceEntityRepository - */ -class TagRepository extends ServiceEntityRepository -{ - public function __construct(ManagerRegistry $registry) - { - parent::__construct($registry, Tag::class); - } -} diff --git a/src/Repository/UserRepository.php b/src/Repository/UserRepository.php index e7a70ff07..d6505d42c 100644 --- a/src/Repository/UserRepository.php +++ b/src/Repository/UserRepository.php @@ -11,8 +11,8 @@ namespace App\Repository; -use App\Entity\User; -use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; +use App\Document\User; +use Doctrine\Bundle\MongoDBBundle\Repository\ServiceDocumentRepository; use Doctrine\Persistence\ManagerRegistry; /** @@ -25,15 +25,22 @@ * @author Ryan Weaver * @author Javier Eguiluz * - * @method User|null findOneByUsername(string $username) - * @method User|null findOneByEmail(string $email) - * - * @template-extends ServiceEntityRepository + * @template-extends ServiceDocumentRepository */ -class UserRepository extends ServiceEntityRepository +class UserRepository extends ServiceDocumentRepository { public function __construct(ManagerRegistry $registry) { parent::__construct($registry, User::class); } + + public function findOneByUsername(string $username): ?User + { + return $this->findOneBy(['username' => $username]); + } + + public function findOneByEmail(string $email): ?User + { + return $this->findOneBy(['email' => $email]); + } } diff --git a/src/Security/PostVoter.php b/src/Security/PostVoter.php index 5df5c3472..c7536bc59 100644 --- a/src/Security/PostVoter.php +++ b/src/Security/PostVoter.php @@ -11,8 +11,8 @@ namespace App\Security; -use App\Entity\Post; -use App\Entity\User; +use App\Document\Post; +use App\Document\User; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authorization\Voter\Vote; use Symfony\Component\Security\Core\Authorization\Voter\Voter; @@ -56,6 +56,8 @@ protected function voteOnAttribute(string $attribute, $post, TokenInterface $tok // the logic of this voter is pretty simple: if the logged-in user is the // author of the given blog post, grant permission; otherwise, deny it. // (the supports() method guarantees that $post is a Post object) + // We can compare objects identity because Doctrine ensure that documents + // with the same ID are the same instance return $user === $post->getAuthor(); } } diff --git a/src/Twig/Components/BlogSearchComponent.php b/src/Twig/Components/BlogSearchComponent.php index 7f14cf8c2..ef63a22e0 100644 --- a/src/Twig/Components/BlogSearchComponent.php +++ b/src/Twig/Components/BlogSearchComponent.php @@ -11,7 +11,7 @@ namespace App\Twig\Components; -use App\Entity\Post; +use App\Document\Post; use App\Repository\PostRepository; use Symfony\UX\LiveComponent\Attribute\AsLiveComponent; use Symfony\UX\LiveComponent\Attribute\LiveProp; diff --git a/symfony.lock b/symfony.lock index e1ea9dc39..d5cb17f2d 100644 --- a/symfony.lock +++ b/symfony.lock @@ -1,131 +1,180 @@ { - "dama/doctrine-test-bundle": { - "version": "8.3", - "recipe": { - "repo": "github.com/symfony/recipes-contrib", - "branch": "main", - "version": "8.3", - "ref": "dfc51177476fb39d014ed89944cde53dc3326d23" - }, - "files": [ - "config/packages/dama_doctrine_test_bundle.yaml" - ] + "dflydev/dot-access-data": { + "version": "v3.0.1" }, - "doctrine/deprecations": { - "version": "1.1", + "doctrine/annotations": { + "version": "1.14", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", - "version": "1.0", - "ref": "87424683adc81d7dc305eefec1fced883084aab9" + "version": "1.10", + "ref": "64d8583af5ea57b7afa4aba4b159907f3a148b05" } }, - "doctrine/doctrine-bundle": { - "version": "2.15", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "2.13", - "ref": "620b57f496f2e599a6015a9fa222c2ee0a32adcb" - }, - "files": [ - "config/packages/doctrine.yaml", - "src/Entity/.gitignore", - "src/Repository/.gitignore" - ] + "doctrine/cache": { + "version": "2.1.1" }, - "doctrine/doctrine-fixtures-bundle": { - "version": "3.6", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "3.0", - "ref": "1f5514cfa15b947298df4d771e694e578d4c204d" - }, - "files": [ - "src/DataFixtures/AppFixtures.php" - ] + "doctrine/collections": { + "version": "1.6.8" }, - "doctrine/doctrine-migrations-bundle": { - "version": "3.3", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "3.1", - "ref": "1d01ec03c6ecbd67c3375c5478c9a423ae5d6a33" - }, - "files": [ - "config/packages/doctrine_migrations.yaml", - "migrations/.gitignore" - ] + "doctrine/deprecations": { + "version": "v0.5.3" }, - "phpstan/phpstan": { - "version": "1.12", + "doctrine/event-manager": { + "version": "1.1.1" + }, + "doctrine/inflector": { + "version": "2.0.4" + }, + "doctrine/instantiator": { + "version": "1.4.0" + }, + "doctrine/lexer": { + "version": "1.2.1" + }, + "doctrine/mongodb-odm-bundle": { + "version": "4.5", "recipe": { "repo": "github.com/symfony/recipes-contrib", "branch": "main", - "version": "1.0", - "ref": "5e490cc197fb6bb1ae22e5abbc531ddc633b6767" + "version": "4.4", + "ref": "a6bc3544da98c97b2eafb2ef1e86bcc8093d96cf" }, "files": [ - "phpstan.dist.neon" + "config/packages/doctrine_mongodb.yaml", + "src/Document/.gitignore" ] }, + "doctrine/persistence": { + "version": "2.2.3" + }, + "egulias/email-validator": { + "version": "3.1.2" + }, + "friendsofphp/proxy-manager-lts": { + "version": "v1.0.5" + }, + "laminas/laminas-code": { + "version": "4.4.3" + }, + "league/commonmark": { + "version": "2.1.0" + }, + "league/config": { + "version": "v1.1.1" + }, + "league/uri": { + "version": "6.5.0" + }, + "league/uri-interfaces": { + "version": "2.3.0" + }, + "masterminds/html5": { + "version": "2.7.5" + }, + "monolog/monolog": { + "version": "2.3.5" + }, + "nette/schema": { + "version": "v1.2.2" + }, + "nette/utils": { + "version": "v3.2.6" + }, + "nikic/php-parser": { + "version": "v4.13.2" + }, + "phpstan/phpstan": { + "version": "1.2.0" + }, "phpunit/phpunit": { "version": "11.5", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", - "version": "11.1", - "ref": "c6658a60fc9d594805370eacdf542c3d6b5c0869" + "version": "9.6", + "ref": "7364a21d87e658eb363c5020c072ecfdc12e2326" }, "files": [ ".env.test", - "phpunit.dist.xml", + "phpunit.xml.dist", "tests/bootstrap.php" ] }, + "psr/cache": { + "version": "3.0.0" + }, + "psr/container": { + "version": "2.0.2" + }, + "psr/event-dispatcher": { + "version": "1.0.0" + }, + "psr/http-message": { + "version": "1.0.1" + }, + "psr/log": { + "version": "1.1.4" + }, "symfony/apache-pack": { "version": "1.0", "recipe": { "repo": "github.com/symfony/recipes-contrib", "branch": "main", "version": "1.0", - "ref": "5d454ec6cc4c700ed3d963f3803e1d427d9669fb" + "ref": "efb318193e48384eb5c5aadff15396ed698f8ffc" }, "files": [ - "./public/.htaccess" + "public/.htaccess" ] }, + "symfony/asset": { + "version": "v6.0.0" + }, "symfony/asset-mapper": { - "version": "7.2", + "version": "6.4", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", "version": "6.4", - "ref": "5ad1308aa756d58f999ffbe1540d1189f5d7d14a" + "ref": "040e08b268490e84a8e05652d6e9d3d49576f1c6" }, "files": [ - "./assets/app.js", - "./assets/styles/app.css", - "./config/packages/asset_mapper.yaml", - "./importmap.php" + "assets/app.js", + "assets/styles/app.css", + "config/packages/asset_mapper.yaml", + "importmap.php" ] }, + "symfony/browser-kit": { + "version": "v6.0.0" + }, + "symfony/cache": { + "version": "v6.0.0" + }, + "symfony/cache-contracts": { + "version": "v3.0.0" + }, + "symfony/config": { + "version": "v6.0.0" + }, "symfony/console": { - "version": "7.2", + "version": "5.3", "recipe": { "repo": "github.com/symfony/recipes", - "branch": "main", + "branch": "master", "version": "5.3", - "ref": "1781ff40d8a17d87cf53f8d4cf0c8346ed2bb461" + "ref": "da0c8be8157600ad34f10ff0c9cc91232522e047" }, "files": [ "bin/console" ] }, + "symfony/css-selector": { + "version": "v6.0.0" + }, "symfony/debug-bundle": { - "version": "7.2", + "version": "6.2", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", @@ -136,41 +185,63 @@ "config/packages/debug.yaml" ] }, + "symfony/dependency-injection": { + "version": "v6.0.0" + }, + "symfony/deprecation-contracts": { + "version": "v3.0.0" + }, + "symfony/doctrine-bridge": { + "version": "v6.0.0" + }, + "symfony/dom-crawler": { + "version": "v6.0.0" + }, + "symfony/dotenv": { + "version": "v6.0.0" + }, + "symfony/error-handler": { + "version": "v6.0.0" + }, + "symfony/event-dispatcher": { + "version": "v6.0.0" + }, + "symfony/event-dispatcher-contracts": { + "version": "v3.0.0" + }, + "symfony/expression-language": { + "version": "v6.0.0" + }, + "symfony/filesystem": { + "version": "v6.0.0" + }, + "symfony/finder": { + "version": "v6.0.0" + }, "symfony/flex": { - "version": "2.4", + "version": "2.2", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", - "version": "2.4", - "ref": "52e9754527a15e2b79d9a610f98185a1fe46622a" + "version": "1.0", + "ref": "146251ae39e06a95be0fe3d13c807bcf3938b172" }, "files": [ - "./.env", - "./.env.dev" + ".env" ] }, "symfony/form": { - "version": "7.2", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "7.2", - "ref": "7d86a6723f4a623f59e2bf966b6aad2fc461d36b" - }, - "files": [ - "./config/packages/csrf.yaml" - ] + "version": "v6.0.0" }, "symfony/framework-bundle": { - "version": "7.3", + "version": "7.0", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", - "version": "7.3", - "ref": "5a1497d539f691b96afd45ae397ce5fe30beb4b9" + "version": "7.0", + "ref": "de6e1b3e2bbbe69e36262d72c3f3db858b1ab391" }, "files": [ - ".editorconfig", "config/packages/cache.yaml", "config/packages/framework.yaml", "config/preload.php", @@ -181,46 +252,76 @@ "src/Kernel.php" ] }, + "symfony/html-sanitizer": { + "version": "v6.1.0-BETA2" + }, + "symfony/http-client": { + "version": "v6.1.0-BETA2" + }, + "symfony/http-client-contracts": { + "version": "v3.0.1" + }, + "symfony/http-foundation": { + "version": "v6.0.0" + }, + "symfony/http-kernel": { + "version": "v6.0.0" + }, + "symfony/intl": { + "version": "v6.0.0" + }, "symfony/mailer": { - "version": "7.2", + "version": "6.2", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", "version": "4.3", - "ref": "09051cfde49476e3c12cd3a0e44289ace1c75a4f" + "ref": "2bf89438209656b85b9a49238c4467bff1b1f939" }, "files": [ - "./config/packages/mailer.yaml" + "config/packages/mailer.yaml" ] }, "symfony/maker-bundle": { - "version": "1.61", + "version": "1.0", "recipe": { "repo": "github.com/symfony/recipes", - "branch": "main", + "branch": "master", "version": "1.0", "ref": "fadbfe33303a76e25cb63401050439aa9b1a9c7f" } }, + "symfony/mime": { + "version": "v6.0.0" + }, + "symfony/monolog-bridge": { + "version": "v6.0.0" + }, "symfony/monolog-bundle": { - "version": "3.10", + "version": "3.8", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", "version": "3.7", - "ref": "aff23899c4440dd995907613c1dd709b6f59503f" + "ref": "213676c4ec929f046dfde5ea8e97625b81bc0578" }, "files": [ "config/packages/monolog.yaml" ] }, + "symfony/options-resolver": { + "version": "v6.0.0" + }, + "symfony/password-hasher": { + "version": "v6.0.0" + }, "symfony/phpunit-bridge": { - "version": "7.2", + "version": "7.0", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", "version": "6.3", - "ref": "a411a0480041243d97382cac7984f7dce7813c08" + "ref": "1f5830c331065b6e4c9d5fa2105e322d29fcd573" }, "files": [ ".env.test", @@ -229,33 +330,48 @@ "tests/bootstrap.php" ] }, + "symfony/polyfill-intl-grapheme": { + "version": "v1.23.1" + }, + "symfony/polyfill-intl-icu": { + "version": "v1.23.0" + }, + "symfony/polyfill-intl-idn": { + "version": "v1.23.0" + }, + "symfony/polyfill-intl-messageformatter": { + "version": "v1.23.0" + }, + "symfony/polyfill-intl-normalizer": { + "version": "v1.23.0" + }, + "symfony/polyfill-mbstring": { + "version": "v1.23.1" + }, + "symfony/property-access": { + "version": "v6.0.0" + }, "symfony/property-info": { - "version": "7.3", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "7.3", - "ref": "dae70df71978ae9226ae915ffd5fad817f5ca1f7" - }, - "files": [ - "config/packages/property_info.yaml" - ] + "version": "v6.0.0" }, "symfony/routing": { - "version": "7.2", + "version": "6.2", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", - "version": "7.0", - "ref": "21b72649d5622d8f7da329ffb5afb232a023619d" + "version": "6.2", + "ref": "e0a11b4ccb8c9e70b574ff5ad3dfdcd41dec5aa6" }, "files": [ "config/packages/routing.yaml", "config/routes.yaml" ] }, + "symfony/runtime": { + "version": "v6.0.0" + }, "symfony/security-bundle": { - "version": "7.2", + "version": "6.4", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", @@ -267,41 +383,64 @@ "config/routes/security.yaml" ] }, + "symfony/security-core": { + "version": "v6.0.0" + }, + "symfony/security-csrf": { + "version": "v6.0.0" + }, + "symfony/security-http": { + "version": "v6.0.0" + }, + "symfony/service-contracts": { + "version": "v3.0.0" + }, "symfony/stimulus-bundle": { - "version": "2.29", + "version": "2.12", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", - "version": "2.20", - "ref": "e058471c5502e549c1404ebdd510099107bb5549" + "version": "2.9", + "ref": "05c45071c7ecacc1e48f94bc43c1f8d4405fb2b2" }, "files": [ "assets/bootstrap.js", "assets/controllers.json", - "assets/controllers/csrf_protection_controller.js", "assets/controllers/hello_controller.js" ] }, + "symfony/stopwatch": { + "version": "v6.0.0" + }, + "symfony/string": { + "version": "v6.0.0" + }, "symfony/translation": { - "version": "7.3", + "version": "6.4", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", "version": "6.3", - "ref": "620a1b84865ceb2ba304c8f8bf2a185fbf32a843" + "ref": "64fe617084223633e1dedf9112935d8c95410d3e" }, "files": [ "config/packages/translation.yaml", "translations/.gitignore" ] }, + "symfony/translation-contracts": { + "version": "v3.0.0" + }, + "symfony/twig-bridge": { + "version": "v6.0.0" + }, "symfony/twig-bundle": { - "version": "7.2", + "version": "6.4", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", - "version": "6.4", - "ref": "cab5fd2a13a45c266d45a7d9337e28dee6272877" + "version": "6.3", + "ref": "b7772eb20e92f3fb4d4fe756e7505b4ba2ca1a2c" }, "files": [ "config/packages/twig.yaml", @@ -309,7 +448,7 @@ ] }, "symfony/ux-icons": { - "version": "2.23", + "version": "2.22", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", @@ -317,62 +456,71 @@ "ref": "803a3bbd5893f9584969ab8670290cdfb6a0a5b5" }, "files": [ - "./assets/icons/symfony.svg" + "assets/icons/symfony.svg" ] }, "symfony/ux-live-component": { - "version": "2.29", + "version": "2.6", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", "version": "2.6", - "ref": "b7130b7b5ddc2f8994bd6149d7c093b184782f0c" + "ref": "73e69baf18f47740d6f58688c5464b10cdacae06" }, "files": [ "config/routes/ux_live_component.yaml" ] }, "symfony/ux-twig-component": { - "version": "2.29", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "2.13", - "ref": "f367ae2a1faf01c503de2171f1ec22567febeead" - }, - "files": [ - "config/packages/twig_component.yaml" - ] + "version": "v2.6.1" }, "symfony/validator": { - "version": "7.2", + "version": "6.2", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", - "version": "7.0", - "ref": "8c1c4e28d26a124b0bb273f537ca8ce443472bfd" + "version": "5.3", + "ref": "c32cfd98f714894c4f128bb99aa2530c1227603c" }, "files": [ "config/packages/validator.yaml" ] }, + "symfony/var-dumper": { + "version": "v6.0.0" + }, + "symfony/var-exporter": { + "version": "v6.0.0" + }, "symfony/web-profiler-bundle": { - "version": "7.3", + "version": "6.2", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", - "version": "7.3", - "ref": "a363460c1b0b4a4d0242f2ce1a843ca0f6ac9026" + "version": "6.1", + "ref": "e42b3f0177df239add25373083a564e5ead4e13a" }, "files": [ "config/packages/web_profiler.yaml", "config/routes/web_profiler.yaml" ] }, + "symfony/yaml": { + "version": "v6.0.0" + }, "symfonycasts/sass-bundle": { - "version": "v0.7.0" + "version": "v0.2.3" }, "twig/extra-bundle": { - "version": "v3.20.0" + "version": "v3.3.4" + }, + "twig/intl-extra": { + "version": "v3.3.4" + }, + "twig/markdown-extra": { + "version": "v3.3.4" + }, + "twig/twig": { + "version": "v3.3.4" } } diff --git a/tests/Command/AbstractCommandTestCase.php b/tests/Command/AbstractCommandTestCase.php index 43aa28388..1bb0bff92 100644 --- a/tests/Command/AbstractCommandTestCase.php +++ b/tests/Command/AbstractCommandTestCase.php @@ -11,12 +11,15 @@ namespace App\Tests\Command; +use App\Tests\ResetFixturesTrait; use Symfony\Bundle\FrameworkBundle\Console\Application; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Symfony\Component\Console\Tester\CommandTester; abstract class AbstractCommandTestCase extends KernelTestCase { + use ResetFixturesTrait; + /** * This helper method abstracts the boilerplate code needed to test the * execution of a command. diff --git a/tests/Command/AddUserCommandTest.php b/tests/Command/AddUserCommandTest.php index 979bffbf4..e682f8f94 100644 --- a/tests/Command/AddUserCommandTest.php +++ b/tests/Command/AddUserCommandTest.php @@ -12,11 +12,14 @@ namespace App\Tests\Command; use App\Repository\UserRepository; +use App\Tests\ResetFixturesTrait; use PHPUnit\Framework\Attributes\DataProvider; use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; final class AddUserCommandTest extends AbstractCommandTestCase { + use ResetFixturesTrait; + /** * @var string[] */ diff --git a/tests/Command/ListUsersCommandTest.php b/tests/Command/ListUsersCommandTest.php index e41e4bdfc..b4c9b256c 100644 --- a/tests/Command/ListUsersCommandTest.php +++ b/tests/Command/ListUsersCommandTest.php @@ -11,10 +11,13 @@ namespace App\Tests\Command; +use App\Tests\ResetFixturesTrait; use PHPUnit\Framework\Attributes\DataProvider; final class ListUsersCommandTest extends AbstractCommandTestCase { + use ResetFixturesTrait; + /** * This test verifies the amount of data is right according to the given parameter max results. */ diff --git a/tests/Controller/Admin/BlogControllerTest.php b/tests/Controller/Admin/BlogControllerTest.php index d7a2c39cc..c5bc114c2 100644 --- a/tests/Controller/Admin/BlogControllerTest.php +++ b/tests/Controller/Admin/BlogControllerTest.php @@ -11,7 +11,7 @@ namespace App\Tests\Controller\Admin; -use App\Entity\User; +use App\Document\User; use App\Repository\PostRepository; use App\Repository\UserRepository; use PHPUnit\Framework\Attributes\DataProvider; diff --git a/tests/Controller/BlogControllerTest.php b/tests/Controller/BlogControllerTest.php index e20f649fe..01c94b86b 100644 --- a/tests/Controller/BlogControllerTest.php +++ b/tests/Controller/BlogControllerTest.php @@ -11,9 +11,10 @@ namespace App\Tests\Controller; -use App\Entity\User; +use App\Document\User; use App\Pagination\Paginator; use App\Repository\UserRepository; +use App\Tests\ResetFixturesTrait; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; /** @@ -28,6 +29,7 @@ */ final class BlogControllerTest extends WebTestCase { + use ResetFixturesTrait; public function testIndex(): void { $client = static::createClient(); diff --git a/tests/Controller/DefaultControllerTest.php b/tests/Controller/DefaultControllerTest.php index a053791e9..ea34044bf 100644 --- a/tests/Controller/DefaultControllerTest.php +++ b/tests/Controller/DefaultControllerTest.php @@ -11,9 +11,11 @@ namespace App\Tests\Controller; -use App\Entity\Post; +use App\Document\Post; +use App\Tests\ResetFixturesTrait; use Doctrine\Bundle\DoctrineBundle\Registry; use PHPUnit\Framework\Attributes\DataProvider; +use Symfony\Bridge\Doctrine\ManagerRegistry; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Component\HttpFoundation\Response; @@ -29,6 +31,8 @@ */ final class DefaultControllerTest extends WebTestCase { + use ResetFixturesTrait; + /** * PHPUnit's data providers allow to execute the same tests repeated times * using a different set of data each time. @@ -58,11 +62,11 @@ public function testPublicBlogPost(): void $client = static::createClient(); // the service container is always available via the test client - /** @var Registry $registry */ - $registry = $client->getContainer()->get('doctrine'); + /** @var ManagerRegistry $registry */ + $registry = $client->getContainer()->get('doctrine_mongodb'); /** @var Post $blogPost */ - $blogPost = $registry->getRepository(Post::class)->find(1); + $blogPost = $registry->getRepository(Post::class)->find('68f14cc10152bda8580dd701'); $client->request('GET', \sprintf('/en/blog/posts/%s', $blogPost->getSlug())); $this->assertResponseIsSuccessful(); @@ -97,7 +101,7 @@ public static function getSecureUrls(): \Generator { yield ['/en/admin/post/']; yield ['/en/admin/post/new']; - yield ['/en/admin/post/1']; - yield ['/en/admin/post/1/edit']; + yield ['/en/admin/post/68f14cc10152bda8580dd701']; + yield ['/en/admin/post/68f14cc10152bda8580dd701/edit']; } } diff --git a/tests/Controller/UserControllerTest.php b/tests/Controller/UserControllerTest.php index 806f733ef..e9666384d 100644 --- a/tests/Controller/UserControllerTest.php +++ b/tests/Controller/UserControllerTest.php @@ -11,8 +11,9 @@ namespace App\Tests\Controller; -use App\Entity\User; +use App\Document\User; use App\Repository\UserRepository; +use App\Tests\ResetFixturesTrait; use PHPUnit\Framework\Attributes\DataProvider; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Component\HttpFoundation\Response; @@ -34,6 +35,8 @@ */ final class UserControllerTest extends WebTestCase { + use ResetFixturesTrait; + #[DataProvider('getUrlsForAnonymousUsers')] public function testAccessDeniedForAnonymousUsers(string $httpMethod, string $url): void { diff --git a/tests/Doctrine/ORM/ConfigurationTest.php b/tests/Doctrine/ODM/ConfigurationTest.php similarity index 93% rename from tests/Doctrine/ORM/ConfigurationTest.php rename to tests/Doctrine/ODM/ConfigurationTest.php index 6d8c90140..93043d75d 100644 --- a/tests/Doctrine/ORM/ConfigurationTest.php +++ b/tests/Doctrine/ODM/ConfigurationTest.php @@ -11,11 +11,13 @@ namespace App\Tests\Doctrine\ORM; -use Doctrine\ORM\Configuration; +use App\Tests\ResetFixturesTrait; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; class ConfigurationTest extends KernelTestCase { + use ResetFixturesTrait; + private function getConfiguration(): Configuration { return static::getContainer()->get('doctrine.orm.default_configuration'); diff --git a/tests/Form/DataTransformer/TagArrayToStringTransformerTest.php b/tests/Form/DataTransformer/TagArrayToStringTransformerTest.php index b79f3c3f3..01e136182 100644 --- a/tests/Form/DataTransformer/TagArrayToStringTransformerTest.php +++ b/tests/Form/DataTransformer/TagArrayToStringTransformerTest.php @@ -11,9 +11,10 @@ namespace App\Tests\Form\DataTransformer; -use App\Entity\Tag; +use App\Document\Tag; use App\Form\DataTransformer\TagArrayToStringTransformer; use App\Repository\TagRepository; +use App\Tests\ResetFixturesTrait; use PHPUnit\Framework\TestCase; /** @@ -23,6 +24,8 @@ */ final class TagArrayToStringTransformerTest extends TestCase { + use ResetFixturesTrait; + /** * Ensures that tags are created correctly. */ diff --git a/tests/ResetFixturesTrait.php b/tests/ResetFixturesTrait.php new file mode 100644 index 000000000..68e9f5844 --- /dev/null +++ b/tests/ResetFixturesTrait.php @@ -0,0 +1,32 @@ +get('doctrine_mongodb.odm.command.load_data_fixtures'); + assert($command instanceof LoadDataFixturesDoctrineODMCommand); + + $input = new ArrayInput([]); + $input->setInteractive(false); + $command->run( + $input, + new NullOutput() + ); + + return $kernel; + } +} \ No newline at end of file diff --git a/tests/object-manager.php b/tests/object-manager.php index b721c1c44..da831d368 100644 --- a/tests/object-manager.php +++ b/tests/object-manager.php @@ -19,4 +19,4 @@ $kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']); $kernel->boot(); -return $kernel->getContainer()->get('doctrine')->getManager(); +return $kernel->getContainer()->get('doctrine_mongodb')->getManager();