From e3a9d5106f7e1d50c8de5e3529ea5c8bcab612a4 Mon Sep 17 00:00:00 2001 From: Nicolas PHILIPPE Date: Sat, 19 Oct 2024 15:09:43 +0200 Subject: [PATCH] wip --- bin/tools/psalm/composer.lock | 462 +++++++++--------- composer.json | 5 +- phpstan.neon | 2 +- psalm.xml | 11 +- src/Persistence/PersistentObjectFactory.php | 44 +- src/Persistence/Proxy.php | 34 ++ .../{ => phpstan}/PersistentObjectFactory.php | 37 +- .../PersistentProxyObjectFactory.php | 41 +- stubs/{ => phpstan}/functions.php | 0 stubs/psalm/PersistentObjectFactory.php | 107 ++++ stubs/psalm/PersistentProxyObjectFactory.php | 107 ++++ stubs/psalm/functions.php | 40 ++ .../FixProxyFactoryMethodsReturnType.php | 57 +++ utils/psalm/FoundryPlugin.php | 18 + 14 files changed, 661 insertions(+), 304 deletions(-) rename stubs/{ => phpstan}/PersistentObjectFactory.php (61%) rename stubs/{ => phpstan}/PersistentProxyObjectFactory.php (55%) rename stubs/{ => phpstan}/functions.php (100%) create mode 100644 stubs/psalm/PersistentObjectFactory.php create mode 100644 stubs/psalm/PersistentProxyObjectFactory.php create mode 100644 stubs/psalm/functions.php create mode 100644 utils/psalm/FixProxyFactoryMethodsReturnType.php create mode 100644 utils/psalm/FoundryPlugin.php diff --git a/bin/tools/psalm/composer.lock b/bin/tools/psalm/composer.lock index 13d03967a..a61d622fb 100644 --- a/bin/tools/psalm/composer.lock +++ b/bin/tools/psalm/composer.lock @@ -8,16 +8,16 @@ "packages": [ { "name": "amphp/amp", - "version": "v2.6.2", + "version": "v2.6.4", "source": { "type": "git", "url": "https://github.com/amphp/amp.git", - "reference": "9d5100cebffa729aaffecd3ad25dc5aeea4f13bb" + "reference": "ded3d9be08f526089eb7ee8d9f16a9768f9dec2d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/amp/zipball/9d5100cebffa729aaffecd3ad25dc5aeea4f13bb", - "reference": "9d5100cebffa729aaffecd3ad25dc5aeea4f13bb", + "url": "https://api.github.com/repos/amphp/amp/zipball/ded3d9be08f526089eb7ee8d9f16a9768f9dec2d", + "reference": "ded3d9be08f526089eb7ee8d9f16a9768f9dec2d", "shasum": "" }, "require": { @@ -29,8 +29,8 @@ "ext-json": "*", "jetbrains/phpstorm-stubs": "^2019.3", "phpunit/phpunit": "^7 | ^8 | ^9", - "psalm/phar": "^3.11@dev", - "react/promise": "^2" + "react/promise": "^2", + "vimeo/psalm": "^3.12" }, "type": "library", "extra": { @@ -85,7 +85,7 @@ "support": { "irc": "irc://irc.freenode.org/amphp", "issues": "https://github.com/amphp/amp/issues", - "source": "https://github.com/amphp/amp/tree/v2.6.2" + "source": "https://github.com/amphp/amp/tree/v2.6.4" }, "funding": [ { @@ -93,20 +93,20 @@ "type": "github" } ], - "time": "2022-02-20T17:52:18+00:00" + "time": "2024-03-21T18:52:26+00:00" }, { "name": "amphp/byte-stream", - "version": "v1.8.1", + "version": "v1.8.2", "source": { "type": "git", "url": "https://github.com/amphp/byte-stream.git", - "reference": "acbd8002b3536485c997c4e019206b3f10ca15bd" + "reference": "4f0e968ba3798a423730f567b1b50d3441c16ddc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/byte-stream/zipball/acbd8002b3536485c997c4e019206b3f10ca15bd", - "reference": "acbd8002b3536485c997c4e019206b3f10ca15bd", + "url": "https://api.github.com/repos/amphp/byte-stream/zipball/4f0e968ba3798a423730f567b1b50d3441c16ddc", + "reference": "4f0e968ba3798a423730f567b1b50d3441c16ddc", "shasum": "" }, "require": { @@ -122,11 +122,6 @@ "psalm/phar": "^3.11.4" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, "autoload": { "files": [ "lib/functions.php" @@ -150,7 +145,7 @@ } ], "description": "A stream abstraction to make working with non-blocking I/O simple.", - "homepage": "http://amphp.org/byte-stream", + "homepage": "https://amphp.org/byte-stream", "keywords": [ "amp", "amphp", @@ -160,9 +155,8 @@ "stream" ], "support": { - "irc": "irc://irc.freenode.org/amphp", "issues": "https://github.com/amphp/byte-stream/issues", - "source": "https://github.com/amphp/byte-stream/tree/v1.8.1" + "source": "https://github.com/amphp/byte-stream/tree/v1.8.2" }, "funding": [ { @@ -170,34 +164,42 @@ "type": "github" } ], - "time": "2021-03-30T17:13:30+00:00" + "time": "2024-04-13T18:00:56+00:00" }, { "name": "composer/pcre", - "version": "3.1.1", + "version": "3.3.1", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9" + "reference": "63aaeac21d7e775ff9bc9d45021e1745c97521c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/00104306927c7a0919b4ced2aaa6782c1e61a3c9", - "reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9", + "url": "https://api.github.com/repos/composer/pcre/zipball/63aaeac21d7e775ff9bc9d45021e1745c97521c4", + "reference": "63aaeac21d7e775ff9bc9d45021e1745c97521c4", "shasum": "" }, "require": { "php": "^7.4 || ^8.0" }, + "conflict": { + "phpstan/phpstan": "<1.11.10" + }, "require-dev": { - "phpstan/phpstan": "^1.3", + "phpstan/phpstan": "^1.11.10", "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^5" + "phpunit/phpunit": "^8 || ^9" }, "type": "library", "extra": { "branch-alias": { "dev-main": "3.x-dev" + }, + "phpstan": { + "includes": [ + "extension.neon" + ] } }, "autoload": { @@ -225,7 +227,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.1.1" + "source": "https://github.com/composer/pcre/tree/3.3.1" }, "funding": [ { @@ -241,28 +243,28 @@ "type": "tidelift" } ], - "time": "2023-10-11T07:11:09+00:00" + "time": "2024-08-27T18:44:43+00:00" }, { "name": "composer/semver", - "version": "3.4.0", + "version": "3.4.3", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32" + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32", - "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32", + "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", "shasum": "" }, "require": { "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^1.4", - "symfony/phpunit-bridge": "^4.2 || ^5" + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" }, "type": "library", "extra": { @@ -306,7 +308,7 @@ "support": { "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.4.0" + "source": "https://github.com/composer/semver/tree/3.4.3" }, "funding": [ { @@ -322,20 +324,20 @@ "type": "tidelift" } ], - "time": "2023-08-31T09:50:34+00:00" + "time": "2024-09-19T14:15:21+00:00" }, { "name": "composer/xdebug-handler", - "version": "3.0.3", + "version": "3.0.5", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "ced299686f41dce890debac69273b47ffe98a40c" + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/ced299686f41dce890debac69273b47ffe98a40c", - "reference": "ced299686f41dce890debac69273b47ffe98a40c", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef", + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef", "shasum": "" }, "require": { @@ -346,7 +348,7 @@ "require-dev": { "phpstan/phpstan": "^1.0", "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^6.0" + "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5" }, "type": "library", "autoload": { @@ -370,9 +372,9 @@ "performance" ], "support": { - "irc": "irc://irc.freenode.org/composer", + "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/3.0.3" + "source": "https://github.com/composer/xdebug-handler/tree/3.0.5" }, "funding": [ { @@ -388,7 +390,7 @@ "type": "tidelift" } ], - "time": "2022-02-25T21:32:43+00:00" + "time": "2024-05-06T16:37:16+00:00" }, { "name": "dnoegel/php-xdg-base-dir", @@ -429,16 +431,16 @@ }, { "name": "doctrine/deprecations", - "version": "1.1.2", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931" + "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/4f2d4f2836e7ec4e7a8625e75c6aa916004db931", - "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", + "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", "shasum": "" }, "require": { @@ -470,9 +472,9 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/1.1.2" + "source": "https://github.com/doctrine/deprecations/tree/1.1.3" }, - "time": "2023-09-27T20:04:15+00:00" + "time": "2024-01-30T19:34:25+00:00" }, { "name": "felixfbecker/advanced-json-rpc", @@ -521,16 +523,16 @@ }, { "name": "felixfbecker/language-server-protocol", - "version": "v1.5.2", + "version": "v1.5.3", "source": { "type": "git", "url": "https://github.com/felixfbecker/php-language-server-protocol.git", - "reference": "6e82196ffd7c62f7794d778ca52b69feec9f2842" + "reference": "a9e113dbc7d849e35b8776da39edaf4313b7b6c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/6e82196ffd7c62f7794d778ca52b69feec9f2842", - "reference": "6e82196ffd7c62f7794d778ca52b69feec9f2842", + "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/a9e113dbc7d849e35b8776da39edaf4313b7b6c9", + "reference": "a9e113dbc7d849e35b8776da39edaf4313b7b6c9", "shasum": "" }, "require": { @@ -571,22 +573,22 @@ ], "support": { "issues": "https://github.com/felixfbecker/php-language-server-protocol/issues", - "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/v1.5.2" + "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/v1.5.3" }, - "time": "2022-03-02T22:36:06+00:00" + "time": "2024-04-30T00:40:11+00:00" }, { "name": "fidry/cpu-core-counter", - "version": "0.5.1", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/theofidry/cpu-core-counter.git", - "reference": "b58e5a3933e541dc286cc91fc4f3898bbc6f1623" + "reference": "8520451a140d3f46ac33042715115e290cf5785f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/b58e5a3933e541dc286cc91fc4f3898bbc6f1623", - "reference": "b58e5a3933e541dc286cc91fc4f3898bbc6f1623", + "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/8520451a140d3f46ac33042715115e290cf5785f", + "reference": "8520451a140d3f46ac33042715115e290cf5785f", "shasum": "" }, "require": { @@ -594,13 +596,13 @@ }, "require-dev": { "fidry/makefile": "^0.2.0", + "fidry/php-cs-fixer-config": "^1.1.2", "phpstan/extension-installer": "^1.2.0", "phpstan/phpstan": "^1.9.2", "phpstan/phpstan-deprecation-rules": "^1.0.0", "phpstan/phpstan-phpunit": "^1.2.2", "phpstan/phpstan-strict-rules": "^1.4.4", - "phpunit/phpunit": "^9.5.26 || ^8.5.31", - "theofidry/php-cs-fixer-config": "^1.0", + "phpunit/phpunit": "^8.5.31 || ^9.5.26", "webmozarts/strict-phpunit": "^7.5" }, "type": "library", @@ -626,7 +628,7 @@ ], "support": { "issues": "https://github.com/theofidry/cpu-core-counter/issues", - "source": "https://github.com/theofidry/cpu-core-counter/tree/0.5.1" + "source": "https://github.com/theofidry/cpu-core-counter/tree/1.2.0" }, "funding": [ { @@ -634,20 +636,20 @@ "type": "github" } ], - "time": "2022-12-24T12:35:10+00:00" + "time": "2024-08-06T10:04:20+00:00" }, { "name": "netresearch/jsonmapper", - "version": "v4.2.0", + "version": "v4.5.0", "source": { "type": "git", "url": "https://github.com/cweiske/jsonmapper.git", - "reference": "f60565f8c0566a31acf06884cdaa591867ecc956" + "reference": "8e76efb98ee8b6afc54687045e1b8dba55ac76e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/f60565f8c0566a31acf06884cdaa591867ecc956", - "reference": "f60565f8c0566a31acf06884cdaa591867ecc956", + "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/8e76efb98ee8b6afc54687045e1b8dba55ac76e5", + "reference": "8e76efb98ee8b6afc54687045e1b8dba55ac76e5", "shasum": "" }, "require": { @@ -658,7 +660,7 @@ "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0", + "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0 || ~10.0", "squizlabs/php_codesniffer": "~3.5" }, "type": "library", @@ -683,31 +685,31 @@ "support": { "email": "cweiske@cweiske.de", "issues": "https://github.com/cweiske/jsonmapper/issues", - "source": "https://github.com/cweiske/jsonmapper/tree/v4.2.0" + "source": "https://github.com/cweiske/jsonmapper/tree/v4.5.0" }, - "time": "2023-04-09T17:37:40+00:00" + "time": "2024-09-08T10:13:13+00:00" }, { "name": "nikic/php-parser", - "version": "v4.18.0", + "version": "v4.19.4", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999" + "reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999", - "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/715f4d25e225bc47b293a8b997fe6ce99bf987d2", + "reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": ">=7.0" + "php": ">=7.1" }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "bin": [ "bin/php-parse" @@ -739,9 +741,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.4" }, - "time": "2023-12-10T21:03:43+00:00" + "time": "2024-09-29T15:01:53+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -798,28 +800,35 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.3.0", + "version": "5.4.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" + "reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c", + "reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c", "shasum": "" }, "require": { + "doctrine/deprecations": "^1.1", "ext-filter": "*", - "php": "^7.2 || ^8.0", + "php": "^7.4 || ^8.0", "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.3", + "phpdocumentor/type-resolver": "^1.7", + "phpstan/phpdoc-parser": "^1.7", "webmozart/assert": "^1.9.1" }, "require-dev": { - "mockery/mockery": "~1.3.2", - "psalm/phar": "^4.8" + "mockery/mockery": "~1.3.5", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-webmozart-assert": "^1.2", + "phpunit/phpunit": "^9.5", + "vimeo/psalm": "^5.13" }, "type": "library", "extra": { @@ -843,33 +852,33 @@ }, { "name": "Jaap van Otterdijk", - "email": "account@ijaap.nl" + "email": "opensource@ijaap.nl" } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.4.1" }, - "time": "2021-10-19T17:43:47+00:00" + "time": "2024-05-21T05:55:05+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "1.7.3", + "version": "1.8.2", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419" + "reference": "153ae662783729388a584b4361f2545e4d841e3c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419", - "reference": "3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/153ae662783729388a584b4361f2545e4d841e3c", + "reference": "153ae662783729388a584b4361f2545e4d841e3c", "shasum": "" }, "require": { "doctrine/deprecations": "^1.0", - "php": "^7.4 || ^8.0", + "php": "^7.3 || ^8.0", "phpdocumentor/reflection-common": "^2.0", "phpstan/phpdoc-parser": "^1.13" }, @@ -907,22 +916,22 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.3" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.8.2" }, - "time": "2023-08-12T11:01:26+00:00" + "time": "2024-02-23T11:10:43+00:00" }, { "name": "phpstan/phpdoc-parser", - "version": "1.24.4", + "version": "1.33.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "6bd0c26f3786cd9b7c359675cb789e35a8e07496" + "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/6bd0c26f3786cd9b7c359675cb789e35a8e07496", - "reference": "6bd0c26f3786cd9b7c359675cb789e35a8e07496", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/82a311fd3690fb2bf7b64d5c98f912b3dd746140", + "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140", "shasum": "" }, "require": { @@ -954,9 +963,9 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.4" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.33.0" }, - "time": "2023-11-26T18:29:22+00:00" + "time": "2024-10-13T11:25:22+00:00" }, { "name": "psr/container", @@ -1013,16 +1022,16 @@ }, { "name": "psr/log", - "version": "3.0.0", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", "shasum": "" }, "require": { @@ -1057,35 +1066,35 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/3.0.0" + "source": "https://github.com/php-fig/log/tree/3.0.2" }, - "time": "2021-07-14T16:46:02+00:00" + "time": "2024-09-11T13:17:53+00:00" }, { "name": "sebastian/diff", - "version": "5.0.3", + "version": "6.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "912dc2fbe3e3c1e7873313cc801b100b6c68c87b" + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/912dc2fbe3e3c1e7873313cc801b100b6c68c87b", - "reference": "912dc2fbe3e3c1e7873313cc801b100b6c68c87b", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^10.0", + "phpunit/phpunit": "^11.0", "symfony/process": "^4.2 || ^5" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -1118,7 +1127,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", "security": "https://github.com/sebastianbergmann/diff/security/policy", - "source": "https://github.com/sebastianbergmann/diff/tree/5.0.3" + "source": "https://github.com/sebastianbergmann/diff/tree/6.0.2" }, "funding": [ { @@ -1126,20 +1135,20 @@ "type": "github" } ], - "time": "2023-05-01T07:48:21+00:00" + "time": "2024-07-03T04:53:05+00:00" }, { "name": "spatie/array-to-xml", - "version": "3.2.2", + "version": "3.3.0", "source": { "type": "git", "url": "https://github.com/spatie/array-to-xml.git", - "reference": "96be97e664c87613121d073ea39af4c74e57a7f8" + "reference": "f56b220fe2db1ade4c88098d83413ebdfc3bf876" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/96be97e664c87613121d073ea39af4c74e57a7f8", - "reference": "96be97e664c87613121d073ea39af4c74e57a7f8", + "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/f56b220fe2db1ade4c88098d83413ebdfc3bf876", + "reference": "f56b220fe2db1ade4c88098d83413ebdfc3bf876", "shasum": "" }, "require": { @@ -1152,6 +1161,11 @@ "spatie/pest-plugin-snapshots": "^1.1" }, "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, "autoload": { "psr-4": { "Spatie\\ArrayToXml\\": "src" @@ -1177,7 +1191,7 @@ "xml" ], "support": { - "source": "https://github.com/spatie/array-to-xml/tree/3.2.2" + "source": "https://github.com/spatie/array-to-xml/tree/3.3.0" }, "funding": [ { @@ -1189,51 +1203,50 @@ "type": "github" } ], - "time": "2023-11-14T14:08:51+00:00" + "time": "2024-05-01T10:20:27+00:00" }, { "name": "symfony/console", - "version": "v6.4.1", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "a550a7c99daeedef3f9d23fb82e3531525ff11fd" + "reference": "0fa539d12b3ccf068a722bbbffa07ca7079af9ee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/a550a7c99daeedef3f9d23fb82e3531525ff11fd", - "reference": "a550a7c99daeedef3f9d23fb82e3531525ff11fd", + "url": "https://api.github.com/repos/symfony/console/zipball/0fa539d12b3ccf068a722bbbffa07ca7079af9ee", + "reference": "0fa539d12b3ccf068a722bbbffa07ca7079af9ee", "shasum": "" }, "require": { - "php": ">=8.1", - "symfony/deprecation-contracts": "^2.5|^3", + "php": ">=8.2", "symfony/polyfill-mbstring": "~1.0", "symfony/service-contracts": "^2.5|^3", - "symfony/string": "^5.4|^6.0|^7.0" + "symfony/string": "^6.4|^7.0" }, "conflict": { - "symfony/dependency-injection": "<5.4", - "symfony/dotenv": "<5.4", - "symfony/event-dispatcher": "<5.4", - "symfony/lock": "<5.4", - "symfony/process": "<5.4" + "symfony/dependency-injection": "<6.4", + "symfony/dotenv": "<6.4", + "symfony/event-dispatcher": "<6.4", + "symfony/lock": "<6.4", + "symfony/process": "<6.4" }, "provide": { "psr/log-implementation": "1.0|2.0|3.0" }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0", "symfony/http-foundation": "^6.4|^7.0", "symfony/http-kernel": "^6.4|^7.0", - "symfony/lock": "^5.4|^6.0|^7.0", - "symfony/messenger": "^5.4|^6.0|^7.0", - "symfony/process": "^5.4|^6.0|^7.0", - "symfony/stopwatch": "^5.4|^6.0|^7.0", - "symfony/var-dumper": "^5.4|^6.0|^7.0" + "symfony/lock": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/stopwatch": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" }, "type": "library", "autoload": { @@ -1267,7 +1280,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.1" + "source": "https://github.com/symfony/console/tree/v7.1.5" }, "funding": [ { @@ -1283,20 +1296,20 @@ "type": "tidelift" } ], - "time": "2023-11-30T10:54:28+00:00" + "time": "2024-09-20T08:28:38+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.4.0", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", "shasum": "" }, "require": { @@ -1305,7 +1318,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -1334,7 +1347,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" }, "funding": [ { @@ -1350,27 +1363,30 @@ "type": "tidelift" } ], - "time": "2023-05-23T14:45:45+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { "name": "symfony/filesystem", - "version": "v6.4.0", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "952a8cb588c3bc6ce76f6023000fb932f16a6e59" + "reference": "61fe0566189bf32e8cfee78335d8776f64a66f5a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/952a8cb588c3bc6ce76f6023000fb932f16a6e59", - "reference": "952a8cb588c3bc6ce76f6023000fb932f16a6e59", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/61fe0566189bf32e8cfee78335d8776f64a66f5a", + "reference": "61fe0566189bf32e8cfee78335d8776f64a66f5a", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.8" }, + "require-dev": { + "symfony/process": "^6.4|^7.0" + }, "type": "library", "autoload": { "psr-4": { @@ -1397,7 +1413,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.4.0" + "source": "https://github.com/symfony/filesystem/tree/v7.1.5" }, "funding": [ { @@ -1413,24 +1429,24 @@ "type": "tidelift" } ], - "time": "2023-07-26T17:27:13+00:00" + "time": "2024-09-17T09:16:35+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.28.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", - "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-ctype": "*" @@ -1440,9 +1456,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -1479,7 +1492,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" }, "funding": [ { @@ -1495,33 +1508,30 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.28.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "875e90aeea2777b6f135677f618529449334a612" + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612", - "reference": "875e90aeea2777b6f135677f618529449334a612", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -1560,7 +1570,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" }, "funding": [ { @@ -1576,33 +1586,30 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.28.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92" + "reference": "3833d7255cc303546435cb650316bff708a1c75c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", - "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -1644,7 +1651,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" }, "funding": [ { @@ -1660,24 +1667,24 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.28.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "42292d99c55abe617799667f454222c54c60e229" + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", - "reference": "42292d99c55abe617799667f454222c54c60e229", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-mbstring": "*" @@ -1687,9 +1694,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -1727,7 +1731,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" }, "funding": [ { @@ -1743,25 +1747,26 @@ "type": "tidelift" } ], - "time": "2023-07-28T09:04:16+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.4.0", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "b3313c2dbffaf71c8de2934e2ea56ed2291a3838" + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/b3313c2dbffaf71c8de2934e2ea56ed2291a3838", - "reference": "b3313c2dbffaf71c8de2934e2ea56ed2291a3838", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", "shasum": "" }, "require": { "php": ">=8.1", - "psr/container": "^2.0" + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" }, "conflict": { "ext-psr": "<1.1|>=2" @@ -1769,7 +1774,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -1809,7 +1814,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.4.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.5.0" }, "funding": [ { @@ -1825,24 +1830,24 @@ "type": "tidelift" } ], - "time": "2023-07-30T20:28:31+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { "name": "symfony/string", - "version": "v6.4.0", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "b45fcf399ea9c3af543a92edf7172ba21174d809" + "reference": "d66f9c343fa894ec2037cc928381df90a7ad4306" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/b45fcf399ea9c3af543a92edf7172ba21174d809", - "reference": "b45fcf399ea9c3af543a92edf7172ba21174d809", + "url": "https://api.github.com/repos/symfony/string/zipball/d66f9c343fa894ec2037cc928381df90a7ad4306", + "reference": "d66f9c343fa894ec2037cc928381df90a7ad4306", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-grapheme": "~1.0", "symfony/polyfill-intl-normalizer": "~1.0", @@ -1852,11 +1857,12 @@ "symfony/translation-contracts": "<2.5" }, "require-dev": { - "symfony/error-handler": "^5.4|^6.0|^7.0", - "symfony/http-client": "^5.4|^6.0|^7.0", - "symfony/intl": "^6.2|^7.0", + "symfony/emoji": "^7.1", + "symfony/error-handler": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^5.4|^6.0|^7.0" + "symfony/var-exporter": "^6.4|^7.0" }, "type": "library", "autoload": { @@ -1895,7 +1901,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.4.0" + "source": "https://github.com/symfony/string/tree/v7.1.5" }, "funding": [ { @@ -1911,20 +1917,20 @@ "type": "tidelift" } ], - "time": "2023-11-28T20:41:49+00:00" + "time": "2024-09-20T08:28:38+00:00" }, { "name": "vimeo/psalm", - "version": "5.17.0", + "version": "5.26.1", "source": { "type": "git", "url": "https://github.com/vimeo/psalm.git", - "reference": "c620f6e80d0abfca532b00bda366062aaedf6e5d" + "reference": "d747f6500b38ac4f7dfc5edbcae6e4b637d7add0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vimeo/psalm/zipball/c620f6e80d0abfca532b00bda366062aaedf6e5d", - "reference": "c620f6e80d0abfca532b00bda366062aaedf6e5d", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/d747f6500b38ac4f7dfc5edbcae6e4b637d7add0", + "reference": "d747f6500b38ac4f7dfc5edbcae6e4b637d7add0", "shasum": "" }, "require": { @@ -1943,11 +1949,11 @@ "ext-tokenizer": "*", "felixfbecker/advanced-json-rpc": "^3.1", "felixfbecker/language-server-protocol": "^1.5.2", - "fidry/cpu-core-counter": "^0.4.1 || ^0.5.1", + "fidry/cpu-core-counter": "^0.4.1 || ^0.5.1 || ^1.0.0", "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0", - "nikic/php-parser": "^4.16", + "nikic/php-parser": "^4.17", "php": "^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0", - "sebastian/diff": "^4.0 || ^5.0", + "sebastian/diff": "^4.0 || ^5.0 || ^6.0", "spatie/array-to-xml": "^2.17.0 || ^3.0", "symfony/console": "^4.1.6 || ^5.0 || ^6.0 || ^7.0", "symfony/filesystem": "^5.4 || ^6.0 || ^7.0" @@ -2021,7 +2027,7 @@ "issues": "https://github.com/vimeo/psalm/issues", "source": "https://github.com/vimeo/psalm" }, - "time": "2023-12-03T20:21:41+00:00" + "time": "2024-09-08T18:53:08+00:00" }, { "name": "webmozart/assert", diff --git a/composer.json b/composer.json index 0e619e8b1..655a3a45b 100644 --- a/composer.json +++ b/composer.json @@ -44,7 +44,10 @@ "symfony/yaml": "^6.4|^7.0" }, "autoload": { - "psr-4": { "Zenstruck\\Foundry\\": "src/" }, + "psr-4": { + "Zenstruck\\Foundry\\": "src/", + "Zenstruck\\Foundry\\Psalm\\": "utils/psalm" + }, "files": ["src/functions.php", "src/Persistence/functions.php", "src/phpunit_helper.php"] }, "autoload-dev": { diff --git a/phpstan.neon b/phpstan.neon index 030b3b5e3..f3e6e4d76 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -4,7 +4,7 @@ parameters: paths: - src - tests - - stubs + - stubs/phpstan ignoreErrors: # suppress strange behavior of PHPStan where it considers proxy() return type as *NEVER* - message: '#Return type of call to function Zenstruck\\Foundry\\Persistence\\proxy contains unresolvable type#' diff --git a/psalm.xml b/psalm.xml index f6647a3ff..2626d2c23 100644 --- a/psalm.xml +++ b/psalm.xml @@ -9,12 +9,11 @@ findUnusedCode="false" > - - + + - - - - + + + diff --git a/src/Persistence/PersistentObjectFactory.php b/src/Persistence/PersistentObjectFactory.php index eb43ba236..d6768a7f1 100644 --- a/src/Persistence/PersistentObjectFactory.php +++ b/src/Persistence/PersistentObjectFactory.php @@ -41,27 +41,23 @@ abstract class PersistentObjectFactory extends ObjectFactory private array $tempAfterPersist = []; /** - * @final - * * @param mixed|Parameters $criteriaOrId * * @return T * * @throws \RuntimeException If no object found */ - public static function find(mixed $criteriaOrId): object + final public static function find(mixed $criteriaOrId): object { return static::repository()->findOrFail($criteriaOrId); } /** - * @final - * * @param Parameters $criteria * * @return T */ - public static function findOrCreate(array $criteria): object + final public static function findOrCreate(array $criteria): object { try { $object = static::repository()->findOneBy($criteria); @@ -73,13 +69,11 @@ public static function findOrCreate(array $criteria): object } /** - * @final - * * @param Parameters $criteria * * @return T */ - public static function randomOrCreate(array $criteria = []): object + final public static function randomOrCreate(array $criteria = []): object { try { return static::repository()->random($criteria); @@ -89,96 +83,80 @@ public static function randomOrCreate(array $criteria = []): object } /** - * @final - * * @param positive-int $count * @param Parameters $criteria * * @return T[] */ - public static function randomSet(int $count, array $criteria = []): array + final public static function randomSet(int $count, array $criteria = []): array { return static::repository()->randomSet($count, $criteria); } /** - * @final - * * @param int<0, max> $min * @param int<0, max> $max * @param Parameters $criteria * * @return T[] */ - public static function randomRange(int $min, int $max, array $criteria = []): array + final public static function randomRange(int $min, int $max, array $criteria = []): array { return static::repository()->randomRange($min, $max, $criteria); } /** - * @final - * * @param Parameters $criteria * * @return T[] */ - public static function findBy(array $criteria): array + final public static function findBy(array $criteria): array { return static::repository()->findBy($criteria); } /** - * @final - * * @param Parameters $criteria * * @return T */ - public static function random(array $criteria = []): object + final public static function random(array $criteria = []): object { return static::repository()->random($criteria); } /** - * @final - * * @return T * * @throws \RuntimeException If no objects exist */ - public static function first(string $sortBy = 'id'): object + final public static function first(string $sortBy = 'id'): object { return static::repository()->firstOrFail($sortBy); } /** - * @final - * * @return T * * @throws \RuntimeException If no objects exist */ - public static function last(string $sortBy = 'id'): object + final public static function last(string $sortBy = 'id'): object { return static::repository()->lastOrFail($sortBy); } /** - * @final - * * @return T[] */ - public static function all(): array + final public static function all(): array { return static::repository()->findAll(); } /** - * @final - * * @return RepositoryDecorator> */ - public static function repository(): ObjectRepository + final public static function repository(): ObjectRepository { Configuration::instance()->assertPersistanceEnabled(); diff --git a/src/Persistence/Proxy.php b/src/Persistence/Proxy.php index cbddf6af7..eaa49192d 100644 --- a/src/Persistence/Proxy.php +++ b/src/Persistence/Proxy.php @@ -21,23 +21,49 @@ */ interface Proxy { + /** + * @psalm-return T&Proxy + * @phpstan-return static + */ public function _enableAutoRefresh(): static; + /** + * @psalm-return T&Proxy + * @phpstan-return static + */ public function _disableAutoRefresh(): static; /** * @param callable(static):void $callback + * @psalm-return T&Proxy + * @phpstan-return static */ public function _withoutAutoRefresh(callable $callback): static; + /** + * @psalm-return T&Proxy + * @phpstan-return static + */ public function _save(): static; + /** + * @psalm-return T&Proxy + * @phpstan-return static + */ public function _refresh(): static; + /** + * @psalm-return T&Proxy + * @phpstan-return static + */ public function _delete(): static; public function _get(string $property): mixed; + /** + * @psalm-return T&Proxy + * @phpstan-return static + */ public function _set(string $property, mixed $value): static; /** @@ -45,8 +71,16 @@ public function _set(string $property, mixed $value): static; */ public function _real(): object; + /** + * @psalm-return T&Proxy + * @phpstan-return static + */ public function _assertPersisted(string $message = '{entity} is not persisted.'): static; + /** + * @psalm-return T&Proxy + * @phpstan-return static + */ public function _assertNotPersisted(string $message = '{entity} is persisted but it should not be.'): static; /** diff --git a/stubs/PersistentObjectFactory.php b/stubs/phpstan/PersistentObjectFactory.php similarity index 61% rename from stubs/PersistentObjectFactory.php rename to stubs/phpstan/PersistentObjectFactory.php index 5d55f7a61..c358d2d8d 100644 --- a/stubs/PersistentObjectFactory.php +++ b/stubs/phpstan/PersistentObjectFactory.php @@ -1,8 +1,6 @@ - */ -class UserRepository extends EntityRepository -{ - public function findByName(string $name): User - { - return new User(); - } -} - /** * The following method stubs are required for auto-completion in PhpStorm * AND phpstan support. @@ -30,9 +17,6 @@ public function findByName(string $name): User * @extends PersistentObjectFactory * * @method User create(array|callable $attributes = []) - * @method static RepositoryDecorator|UserRepository repository() - * - * @phpstan-method static RepositoryDecorator repository() */ final class UserFactory extends PersistentObjectFactory { @@ -47,6 +31,26 @@ protected function defaults(): array|callable } } +assertType('User', UserFactory::new()->create()); +assertType('User', UserFactory::createOne()); +assertType('User', UserFactory::new()->many(2)->create()[0]); +assertType('User', UserFactory::new()->sequence([])->create()[0]); +assertType('User', UserFactory::first()); +assertType('User', UserFactory::last()); +assertType('User', UserFactory::find(1)); +assertType('User', UserFactory::random()); +assertType('User', UserFactory::findOrCreate([])); +assertType('User', UserFactory::randomOrCreate()); +assertType('User|null', UserFactory::repository()->find(1)); +assertType("array", UserFactory::all()); +assertType("array", UserFactory::createMany(1)); +assertType("array", UserFactory::createSequence([])); +assertType("array", UserFactory::randomRange(1, 2)); +assertType("array", UserFactory::randomSet(2)); +assertType("array", UserFactory::findBy(['name' => 'foo'])); +assertType("array", UserFactory::repository()->findAll()); +assertType("Zenstruck\Foundry\Persistence\RepositoryDecorator>", UserFactory::repository()); + // test autocomplete with phpstorm assertType('string', UserFactory::new()->create()->name); assertType('string', UserFactory::createOne()->name); @@ -64,7 +68,6 @@ protected function defaults(): array|callable assertType('string', UserFactory::randomOrCreate([])->name); assertType('string|null', UserFactory::repository()->find(1)?->name); assertType('string', UserFactory::repository()->findAll()[0]->name); -assertType('string', UserFactory::repository()->findByName('foo')->name); assertType('int', UserFactory::repository()->count()); assertType('string', proxy(UserFactory::createOne())->name); assertType('string', proxy(UserFactory::new()->create())->name); diff --git a/stubs/PersistentProxyObjectFactory.php b/stubs/phpstan/PersistentProxyObjectFactory.php similarity index 55% rename from stubs/PersistentProxyObjectFactory.php rename to stubs/phpstan/PersistentProxyObjectFactory.php index c6a254f7b..9833b6bca 100644 --- a/stubs/PersistentProxyObjectFactory.php +++ b/stubs/phpstan/PersistentProxyObjectFactory.php @@ -1,8 +1,6 @@ - */ -class UserRepository1 extends EntityRepository -{ - public function findByName(string $name): User1 - { - return new User1(); - } -} - /** * The following method stubs are required for auto-completion in PhpStorm * AND phpstan support. * * @extends PersistentProxyObjectFactory - * - * @method static RepositoryDecorator|UserRepository1 repository() - * - * @phpstan-method static RepositoryDecorator repository() */ final class User1Factory extends PersistentProxyObjectFactory { @@ -45,6 +28,29 @@ protected function defaults(): array|callable } } +$proxyType = 'User1&Zenstruck\Foundry\Persistence\Proxy'; +assertType('User1', User1Factory::new()->create()->_real()); +assertType($proxyType, User1Factory::new()->create()); +assertType($proxyType, User1Factory::new()->create()->_refresh()); +assertType($proxyType, User1Factory::createOne()); +assertType($proxyType, User1Factory::new()->many(2)->create()[0]); +assertType($proxyType, User1Factory::new()->sequence([])->create()[0]); +assertType($proxyType, User1Factory::first()); +assertType($proxyType, User1Factory::last()); +assertType($proxyType, User1Factory::find(1)); +assertType($proxyType, User1Factory::random()); +assertType($proxyType, User1Factory::findOrCreate([])); +assertType($proxyType, User1Factory::randomOrCreate()); +assertType("array<{$proxyType}>", User1Factory::all()); +assertType("array<{$proxyType}>", User1Factory::createMany(1)); +assertType("array<{$proxyType}>", User1Factory::createSequence([])); +assertType("array<{$proxyType}>", User1Factory::randomRange(1, 2)); +assertType("array<{$proxyType}>", User1Factory::randomSet(2)); +assertType("array<{$proxyType}>", User1Factory::findBy(['name' => 'foo'])); +assertType("({$proxyType})|null", User1Factory::repository()->find(1)); +assertType("array<{$proxyType}>", User1Factory::repository()->findAll()); +assertType("Zenstruck\Foundry\Persistence\RepositoryDecorator<{$proxyType}, Doctrine\Persistence\ObjectRepository<{$proxyType}>>", User1Factory::repository()); + // test autocomplete with phpstorm assertType('string', User1Factory::new()->create()->_refresh()->name); assertType('string', User1Factory::createOne()->_refresh()->name); @@ -62,5 +68,4 @@ protected function defaults(): array|callable assertType('string', User1Factory::randomOrCreate([])->_refresh()->name); assertType('string|null', User1Factory::repository()->find(1)?->name); assertType('string', User1Factory::repository()->findAll()[0]->name); -assertType('string', User1Factory::repository()->findByName('foo')->name); assertType('int', User1Factory::repository()->count()); diff --git a/stubs/functions.php b/stubs/phpstan/functions.php similarity index 100% rename from stubs/functions.php rename to stubs/phpstan/functions.php diff --git a/stubs/psalm/PersistentObjectFactory.php b/stubs/psalm/PersistentObjectFactory.php new file mode 100644 index 000000000..1d8d67c7e --- /dev/null +++ b/stubs/psalm/PersistentObjectFactory.php @@ -0,0 +1,107 @@ + + */ +final class UserFactory extends PersistentObjectFactory +{ + public static function class(): string + { + return User::class; + } + + protected function defaults(): array|callable + { + return []; + } +} + +/** @psalm-check-type-exact $var = User */ +$var = UserFactory::new()->create(); +/** @psalm-check-type-exact $var = User */ +$var = UserFactory::createOne(); +/** @psalm-check-type-exact $var = User */ +$var = UserFactory::new()->many(2)->create()[0]; +/** @psalm-check-type-exact $var = User */ +$var = UserFactory::new()->sequence([])->create()[0]; +/** @psalm-check-type-exact $var = User */ +$var = UserFactory::createMany(1)[0]; +/** @psalm-check-type-exact $var = User */ +$var = UserFactory::createSequence([])[0]; +/** @psalm-check-type-exact $var = User */ +$var = UserFactory::first(); +/** @psalm-check-type-exact $var = User */ +$var = UserFactory::last(); +/** @psalm-check-type-exact $var = User */ +$var = UserFactory::find(1); +/** @psalm-check-type-exact $var = array */ +$var = UserFactory::all(); +/** @psalm-check-type-exact $var = User */ +$var = UserFactory::random(); +/** @psalm-check-type-exact $var = array */ +$var = UserFactory::randomRange(1, 2); +/** @psalm-check-type-exact $var = array */ +$var = UserFactory::randomSet(2); +/** @psalm-check-type-exact $var = array */ +$var = UserFactory::findBy(['name' => 'foo']); +/** @psalm-check-type-exact $var = User */ +$var = UserFactory::findOrCreate([]); +/** @psalm-check-type-exact $var = User */ +$var = UserFactory::randomOrCreate(); +/** @psalm-check-type-exact $var = User|null */ +$var = UserFactory::repository()->find(1); +/** @psalm-check-type-exact $var = array */ +$var = UserFactory::repository()->findAll(); +/** @psalm-check-type-exact $var = Zenstruck\Foundry\Persistence\RepositoryDecorator> */ +$var = UserFactory::repository(); + +// test autocomplete with phpstorm +/** @psalm-check-type-exact $var = string */ +$var = UserFactory::new()->create()->name; +/** @psalm-check-type-exact $var = string */ +$var = UserFactory::createOne()->name; +/** @psalm-check-type-exact $var = string */ +$var = UserFactory::new()->many(2)->create()[0]->name; +/** @psalm-check-type-exact $var = string */ +$var = UserFactory::createMany(1)[0]->name; +/** @psalm-check-type-exact $var = string */ +$var = UserFactory::first()->name; +/** @psalm-check-type-exact $var = string */ +$var = UserFactory::last()->name; +/** @psalm-check-type-exact $var = string */ +$var = UserFactory::find(1)->name; +/** @psalm-check-type-exact $var = string */ +$var = UserFactory::all()[0]->name; +/** @psalm-check-type-exact $var = string */ +$var = UserFactory::random()->name; +/** @psalm-check-type-exact $var = string */ +$var = UserFactory::randomRange(1, 2)[0]->name; +/** @psalm-check-type-exact $var = string */ +$var = UserFactory::randomSet(2)[0]->name; +/** @psalm-check-type-exact $var = string */ +$var = UserFactory::findBy(['name' => 'foo'])[0]->name; +/** @psalm-check-type-exact $var = string */ +$var = UserFactory::findOrCreate([])->name; +/** @psalm-check-type-exact $var = string */ +$var = UserFactory::randomOrCreate([])->name; +/** @psalm-check-type-exact $var = string|null */ +$var = UserFactory::repository()->find(1)?->name; +/** @psalm-check-type-exact $var = string */ +$var = UserFactory::repository()->findAll()[0]->name; +/** @psalm-check-type-exact $var = int */ +$var = UserFactory::repository()->count(); +/** @psalm-check-type-exact $var = string */ +$var = proxy(UserFactory::createOne())->name; +/** @psalm-check-type-exact $var = string */ +$var = proxy(UserFactory::new()->create())->name; diff --git a/stubs/psalm/PersistentProxyObjectFactory.php b/stubs/psalm/PersistentProxyObjectFactory.php new file mode 100644 index 000000000..bf265bcf4 --- /dev/null +++ b/stubs/psalm/PersistentProxyObjectFactory.php @@ -0,0 +1,107 @@ + + */ +final class User1Factory extends PersistentProxyObjectFactory +{ + public static function class(): string + { + return User1::class; + } + + protected function defaults(): array|callable + { + return []; + } +} + +/** @psalm-check-type-exact $var = User1&Proxy */ +$var = User1Factory::new()->create(); +/** @psalm-check-type-exact $var = User1&Proxy */ +$var = User1Factory::new()->create()->_refresh(); +/** @psalm-check-type-exact $var = User1 */ +$var = User1Factory::new()->create()->_real(); +/** @psalm-check-type-exact $var = User1&Proxy */ +$var = User1Factory::createOne(); +/** @psalm-check-type-exact $var = User1&Proxy */ +$var = User1Factory::first(); +/** @psalm-check-type-exact $var = User1&Proxy */ +$var = User1Factory::last(); +/** @psalm-check-type-exact $var = User1&Proxy */ +$var = User1Factory::find(1); +/** @psalm-check-type-exact $var = User1&Proxy */ +$var = User1Factory::random(); +/** @psalm-check-type-exact $var = User1&Proxy */ +$var = User1Factory::findOrCreate([]); +/** @psalm-check-type-exact $var = User1&Proxy */ +$var = User1Factory::randomOrCreate(); +/** @psalm-check-type-exact $var = User1&Proxy */ +$var = User1Factory::new()->many(2)->create()[0]; +/** @psalm-check-type-exact $var = User1&Proxy */ +$var = User1Factory::new()->sequence([])->create()[0]; +/** @psalm-check-type-exact $var = list> */ +$var = User1Factory::createMany(1); +/** @psalm-check-type-exact $var = list> */ +$var = User1Factory::createSequence([]); +/** @psalm-check-type-exact $var = list> */ +$var = User1Factory::all(); +/** @psalm-check-type-exact $var = list> */ +$var = User1Factory::randomRange(1, 2); +/** @psalm-check-type-exact $var = list> */ +$var = User1Factory::randomSet(2); +/** @psalm-check-type-exact $var = list> */ +$var = User1Factory::findBy(['name' => 'foo']); +/** @psalm-check-type-exact $var = (User1&Proxy)|null */ +$var = User1Factory::repository()->find(1); +/** @psalm-check-type-exact $var = array> */ +$var = User1Factory::repository()->findAll(); +/** @psalm-check-type-exact $var = \Zenstruck\Foundry\Persistence\RepositoryDecorator, \Doctrine\Persistence\ObjectRepository> */ +$var = User1Factory::repository(); + +/** @psalm-check-type-exact $var = string */ +$var = User1Factory::new()->create()->_refresh()->name; +/** @psalm-check-type-exact $var = string */ +$var = User1Factory::createOne()->_refresh()->name; +/** @psalm-check-type-exact $var = string */ +$var = User1Factory::new()->many(2)->create()[0]->_refresh()->name; +/** @psalm-check-type-exact $var = string */ +$var = User1Factory::createMany(1)[0]->_refresh()->name; +/** @psalm-check-type-exact $var = string */ +$var = User1Factory::first()->_refresh()->name; +/** @psalm-check-type-exact $var = string */ +$var = User1Factory::last()->_refresh()->name; +/** @psalm-check-type-exact $var = string */ +$var = User1Factory::find(1)->_refresh()->name; +/** @psalm-check-type-exact $var = string */ +$var = User1Factory::all()[0]->_refresh()->name; +/** @psalm-check-type-exact $var = string */ +$var = User1Factory::random()->_refresh()->name; +/** @psalm-check-type-exact $var = string */ +$var = User1Factory::randomRange(1, 2)[0]->_refresh()->name; +/** @psalm-check-type-exact $var = string */ +$var = User1Factory::randomSet(2)[0]->_refresh()->name; +/** @psalm-check-type-exact $var = string */ +$var = User1Factory::findBy(['name' => 'foo'])[0]->_refresh()->name; +/** @psalm-check-type-exact $var = string */ +$var = User1Factory::findOrCreate([])->_refresh()->name; +/** @psalm-check-type-exact $var = string */ +$var = User1Factory::randomOrCreate([])->_refresh()->name; +/** @psalm-check-type-exact $var = string|null */ +$var = User1Factory::repository()->find(1)?->name; +/** @psalm-check-type-exact $var = string */ +$var = User1Factory::repository()->findAll()[0]->name; +/** @psalm-check-type-exact $var = int */ +$var = User1Factory::repository()->count(); diff --git a/stubs/psalm/functions.php b/stubs/psalm/functions.php new file mode 100644 index 000000000..8fce8aebb --- /dev/null +++ b/stubs/psalm/functions.php @@ -0,0 +1,40 @@ +create(); + +/** @psalm-check-type-exact $user = MyUser */ +$user = object(MyUser::class); + +/** @psalm-check-type-exact $user = MyUser */ +$user = persistent_factory(MyUser::class)->create(); + +/** @psalm-check-type-exact $user = MyUser */ +$user = persist(MyUser::class); + +/** @psalm-check-type-exact $user = MyUser|null */ +$user = repository(MyUser::class)->find(1); + +/** @psalm-check-type-exact $user = MyUser&Zenstruck\Foundry\Persistence\Proxy */ +$user = proxy(object(MyUser::class)); + +/** @psalm-check-type-exact $name = string */ +$name = proxy(object(MyUser::class))->name; + +/** @psalm-check-type-exact $user = MyUser&Zenstruck\Foundry\Persistence\Proxy */ +$user = proxy(object(MyUser::class))->_refresh(); diff --git a/utils/psalm/FixProxyFactoryMethodsReturnType.php b/utils/psalm/FixProxyFactoryMethodsReturnType.php new file mode 100644 index 000000000..0e40124d7 --- /dev/null +++ b/utils/psalm/FixProxyFactoryMethodsReturnType.php @@ -0,0 +1,57 @@ +getMethodId()); + + if ($event->getCodebase()->classExtends($class, PersistentProxyObjectFactory::class)) { + $templateType = $event->getCodebase()->classlikes->getStorageFor($class)->template_extended_params[PersistentProxyObjectFactory::class]['T'] ?? null; + + if (!$templateType) { + return; + } + + $templateTypeAsString = $templateType->getId(); + $proxyTypeHint = "{$templateTypeAsString}&Zenstruck\\Foundry\\Persistence\\Proxy<{$templateTypeAsString}>"; + + $methodsReturningObject = ['create', 'createone', 'first', 'last', 'find', 'random', 'findorcreate', 'randomorcreate']; + if (\in_array($method, $methodsReturningObject, true)) { + $event->setReturnTypeCandidate(Type::parseString($proxyTypeHint)); + } + + $methodsReturningListOfObjects = ['createmany', 'randomrange', 'randomset', 'findby', 'all', 'createsequence']; + if (\in_array($method, $methodsReturningListOfObjects, true)) { + $event->setReturnTypeCandidate(Type::parseString("list<{$proxyTypeHint}>")); + } + + $methodsReturningFactoryCollection = ['many', 'sequence']; + if (\in_array($method, $methodsReturningFactoryCollection, true)) { + $factoryCollectionClass = FactoryCollection::class; + $event->setReturnTypeCandidate(Type::parseString("{$factoryCollectionClass}<{$proxyTypeHint}>")); + } + + if ($method === 'repository' + // if user has overridden the repository() method, we should not change the return type + && str_starts_with($event->getReturnTypeCandidate()->getId(), RepositoryDecorator::class) + ) { + $repositoryDecoratorClass = RepositoryDecorator::class; + $doctrineRepositoryClass = ObjectRepository::class; + $event->setReturnTypeCandidate(Type::parseString("{$repositoryDecoratorClass}<{$proxyTypeHint}, {$doctrineRepositoryClass}<$templateTypeAsString>>")); + } + } + } +} diff --git a/utils/psalm/FoundryPlugin.php b/utils/psalm/FoundryPlugin.php new file mode 100644 index 000000000..a9079a121 --- /dev/null +++ b/utils/psalm/FoundryPlugin.php @@ -0,0 +1,18 @@ +registerHooksFromClass(FixProxyFactoryMethodsReturnType::class); + } +}