From 79649c3d757e63ea66410b95b05d42722fcd9334 Mon Sep 17 00:00:00 2001 From: Andrew Longosz Date: Thu, 11 Sep 2025 15:55:33 +0200 Subject: [PATCH 1/3] Fixed issues uncovered by PHPStan v2.1.23 (#649) For more details see https://github.com/ibexa/core/pull/649 Key changes: * [BinaryFile Field Type] Removed redundant override of the * [Media Field Type] Removed redundant override of the * [Cache] Improved PersistenceLogger code quality * [ConfigResolver] Removed redundant check if the `function` key exists * [ViewProviders] Fixed the incorrect type hint of `Registry::$viewProviders` * [ImageConverter] Handled possible null reference when parsing legacy XML * [Tests] Added coverage for improved parts of PersistenceLogger * [Tests] Fixed type hints in RelationSearchBaseIntegrationTestTrait * [Tests] Fixed return type hints in UI Translation VOs tests * [Country Field Type] Improved data integrity checking when converting to/from storage values * [PHPStan] Removed resolved issues from the baseline * [PHPStan] Regenerated baseline for PHP >= 8.0 --- phpstan-baseline-7.4.neon | 72 ----- phpstan-baseline-gte-8.0.neon | 280 ++++++++++-------- phpstan-baseline.neon | 180 ----------- .../Configuration/ConfigResolver.php | 2 +- src/lib/FieldType/BinaryFile/Type.php | 15 - src/lib/FieldType/Media/Type.php | 27 -- .../MVC/Symfony/View/Provider/Registry.php | 2 +- .../Persistence/Cache/PersistenceLogger.php | 16 +- .../FieldValue/Converter/CountryConverter.php | 6 +- .../FieldValue/Converter/ImageConverter.php | 9 +- ...RelationSearchBaseIntegrationTestTrait.php | 22 +- .../Cache/PersistenceLoggerTest.php | 71 ++++- .../Values/Translation/MessageTest.php | 2 +- .../Values/Translation/PluralTest.php | 2 +- 14 files changed, 247 insertions(+), 459 deletions(-) diff --git a/phpstan-baseline-7.4.neon b/phpstan-baseline-7.4.neon index 04ac64b05c..33547e3bc3 100644 --- a/phpstan-baseline-7.4.neon +++ b/phpstan-baseline-7.4.neon @@ -6,24 +6,6 @@ parameters: count: 1 path: src/bundle/Core/ApiLoader/StorageConnectionFactory.php - - - message: '#^Parameter \#1 \$input of function array_filter expects array, iterable\ given\.$#' - identifier: argument.type - count: 1 - path: src/bundle/Core/Command/CleanupVersionsCommand.php - - - - message: '#^Parameter \#1 \$input of function array_slice expects array, iterable\ given\.$#' - identifier: argument.type - count: 1 - path: src/bundle/Core/Command/CleanupVersionsCommand.php - - - - message: '#^Parameter \#1 \$var of function count expects array\|Countable, iterable\ given\.$#' - identifier: argument.type - count: 1 - path: src/bundle/Core/Command/CleanupVersionsCommand.php - - message: '#^Parameter \#2 \$str of function fwrite expects string, string\|false given\.$#' identifier: argument.type @@ -198,12 +180,6 @@ parameters: count: 1 path: src/lib/MVC/Symfony/Component/Serializer/AbstractPropertyWhitelistNormalizer.php - - - message: '#^Parameter \#1 \$input of function array_keys expects array, iterable\ given\.$#' - identifier: argument.type - count: 1 - path: src/lib/MVC/Symfony/FieldType/RelationList/ParameterProvider.php - - message: '#^Parameter \#1 \$arr1 of function array_merge expects array, iterable\ given\.$#' identifier: argument.type @@ -246,18 +222,6 @@ parameters: count: 1 path: src/lib/Persistence/Cache/UrlWildcardHandler.php - - - message: '#^Parameter \#2 \$pieces of function implode expects array, array\|bool\|float\|int\|string given\.$#' - identifier: argument.type - count: 1 - path: src/lib/Persistence/Legacy/Content/FieldValue/Converter/CountryConverter.php - - - - message: '#^Parameter \#2 \$pieces of function implode expects array, array\|float\|int\\|int\<1, max\>\|string\|true given\.$#' - identifier: argument.type - count: 1 - path: src/lib/Persistence/Legacy/Content/FieldValue/Converter/CountryConverter.php - - message: '#^Cannot access property \$ownerDocument on DOMElement\|false\.$#' identifier: property.nonObject @@ -360,12 +324,6 @@ parameters: count: 1 path: src/lib/Search/Legacy/Content/Location/Gateway/CriterionHandler/Ancestor.php - - - message: '#^Parameter \#1 \$object of method ReflectionProperty\:\:getValue\(\) expects object, object\|null given\.$#' - identifier: argument.type - count: 1 - path: tests/bundle/Core/DependencyInjection/Compiler/SlugConverterConfigurationPassTest.php - - message: '#^Parameter \#1 \$var of function count expects array\|Countable, array\|bool\|float\|int\|string\|null given\.$#' identifier: argument.type @@ -414,24 +372,6 @@ parameters: count: 1 path: tests/integration/Core/Repository/BaseTest.php - - - message: '#^Parameter \#1 \$var of function count expects array\|Countable, iterable\ given\.$#' - identifier: argument.type - count: 4 - path: tests/integration/Core/Repository/ContentServiceAuthorizationTest.php - - - - message: '#^Parameter \#1 \$array_arg of function usort expects TArray of array, iterable\ given\.$#' - identifier: argument.type - count: 2 - path: tests/integration/Core/Repository/ContentServiceTest.php - - - - message: '#^Parameter \#1 \$input of function array_keys expects array, iterable\ given\.$#' - identifier: argument.type - count: 1 - path: tests/integration/Core/Repository/ContentServiceTest.php - - message: '#^Parameter \#1 \$input of function array_values expects array\, iterable\ given\.$#' identifier: argument.type @@ -450,18 +390,6 @@ parameters: count: 1 path: tests/integration/Core/Repository/ContentServiceTest.php - - - message: '#^Parameter \#1 \$var of function count expects array\|Countable, iterable\ given\.$#' - identifier: argument.type - count: 1 - path: tests/integration/Core/Repository/ContentServiceTest.php - - - - message: '#^Parameter \#1 \$var of function count expects array\|Countable, iterable\ given\.$#' - identifier: argument.type - count: 2 - path: tests/integration/Core/Repository/ContentServiceTest.php - - message: '#^Parameter \#1 \$var of function count expects array\|Countable, iterable\ given\.$#' identifier: argument.type diff --git a/phpstan-baseline-gte-8.0.neon b/phpstan-baseline-gte-8.0.neon index c7eda9583c..66ecc07e72 100644 --- a/phpstan-baseline-gte-8.0.neon +++ b/phpstan-baseline-gte-8.0.neon @@ -1,431 +1,451 @@ parameters: ignoreErrors: - - message: "#^Parameter \\#1 \\$array of function array_keys expects array, array\\|bool\\|float\\|int\\|string\\|null given\\.$#" + message: '#^Parameter \#1 \$array of function array_keys expects array, array\|bool\|float\|int\|string\|null given\.$#' + identifier: argument.type count: 1 path: src/bundle/Core/ApiLoader/StorageConnectionFactory.php - - message: "#^Parameter \\#1 \\$array of function array_filter expects array, iterable\\ given\\.$#" - count: 1 - path: src/bundle/Core/Command/CleanupVersionsCommand.php - - - - message: "#^Parameter \\#1 \\$array of function array_slice expects array, iterable\\ given\\.$#" - count: 1 - path: src/bundle/Core/Command/CleanupVersionsCommand.php - - - - message: "#^Parameter \\#1 \\$value of function count expects array\\|Countable, iterable\\ given\\.$#" - count: 1 - path: src/bundle/Core/Command/CleanupVersionsCommand.php - - - - message: "#^Parameter \\#2 \\$data of function fwrite expects string, string\\|false given\\.$#" + message: '#^Parameter \#2 \$data of function fwrite expects string, string\|false given\.$#' + identifier: argument.type count: 1 path: src/bundle/Core/Command/ResizeOriginalImagesCommand.php - - message: "#^Parameter \\#2 \\.\\.\\.\\$arrays of function array_merge expects array, Ibexa\\\\Contracts\\\\Core\\\\SiteAccess\\\\ConfigResolverInterface given\\.$#" + message: '#^Parameter \#2 \.\.\.\$arrays of function array_merge expects array, Ibexa\\Contracts\\Core\\SiteAccess\\ConfigResolverInterface given\.$#' + identifier: argument.type count: 1 path: src/bundle/Core/DependencyInjection/Configuration/ChainConfigResolver.php - - message: "#^Parameter \\#1 \\$string of function strtolower expects string, string\\|null given\\.$#" + message: '#^Parameter \#1 \$string of function strtolower expects string, string\|null given\.$#' + identifier: argument.type count: 1 path: src/bundle/Core/DependencyInjection/Configuration/ConfigResolver.php - - message: "#^Parameter \\#1 \\$array of function array_shift expects array, array\\|bool\\|float\\|int\\|string\\|null given\\.$#" + message: '#^Parameter \#1 \$array of function array_shift expects array, array\|bool\|float\|int\|string\|null given\.$#' + identifier: argument.type count: 1 path: src/bundle/Core/DependencyInjection/Configuration/Parser/Languages.php - - message: "#^Parameter \\#1 \\.\\.\\.\\$arrays of function array_merge expects array, array\\|bool\\|float\\|int\\|string\\|null given\\.$#" + message: '#^Parameter \#1 \.\.\.\$arrays of function array_merge expects array, array\|bool\|float\|int\|string\|null given\.$#' + identifier: argument.type count: 1 path: src/bundle/Core/DependencyInjection/Configuration/SiteAccessAware/Contextualizer.php - - message: "#^Parameter \\#1 \\.\\.\\.\\$arrays of function array_merge expects array, array\\|bool\\|float\\|int\\|string\\|null given\\.$#" + message: '#^Parameter \#1 \.\.\.\$arrays of function array_merge expects array, array\|bool\|float\|int\|string\|null given\.$#' + identifier: argument.type count: 1 path: src/bundle/Core/DependencyInjection/IbexaCoreExtension.php - - message: "#^Parameter \\#3 \\$length of function substr expects int\\|null, int\\<0, max\\>\\|false given\\.$#" + message: '#^Parameter \#3 \$length of function substr expects int\|null, int\<0, max\>\|false given\.$#' + identifier: argument.type count: 1 path: src/bundle/Core/Features/Context/ContentPreviewContext.php - - message: "#^Parameter \\#1 \\$value of function count expects array\\|Countable, iterable\\ given\\.$#" + message: '#^Parameter \#1 \$value of function count expects array\|Countable, iterable\ given\.$#' + identifier: argument.type count: 1 path: src/bundle/Core/Features/Context/UserContext.php - - message: "#^Parameter \\#2 \\$data of function fwrite expects string, string\\|false given\\.$#" + message: '#^Parameter \#2 \$data of function fwrite expects string, string\|false given\.$#' + identifier: argument.type count: 1 path: src/bundle/Core/Imagine/IORepositoryResolver.php - - message: "#^Method Ibexa\\\\Bundle\\\\Core\\\\URLChecker\\\\Handler\\\\HTTPHandler\\:\\:createCurlHandlerForUrl\\(\\) should return resource but returns \\(CurlHandle\\|false\\)\\.$#" + message: '#^Method Ibexa\\Bundle\\Core\\URLChecker\\Handler\\HTTPHandler\:\:createCurlHandlerForUrl\(\) should return resource but returns \(CurlHandle\|false\)\.$#' + identifier: return.type count: 1 path: src/bundle/Core/URLChecker/Handler/HTTPHandler.php - - message: "#^Parameter \\#1 \\$handle of function curl_getinfo expects CurlHandle, resource given\\.$#" + message: '#^Parameter \#1 \$handle of function curl_getinfo expects CurlHandle, resource given\.$#' + identifier: argument.type count: 1 path: src/bundle/Core/URLChecker/Handler/HTTPHandler.php - - message: "#^Parameter \\#2 \\$handle of function curl_multi_add_handle expects CurlHandle, resource given\\.$#" + message: '#^Parameter \#2 \$handle of function curl_multi_add_handle expects CurlHandle, resource given\.$#' + identifier: argument.type count: 2 path: src/bundle/Core/URLChecker/Handler/HTTPHandler.php - - message: "#^Parameter \\#1 \\$stream of function fclose expects resource, resource\\|false given\\.$#" + message: '#^Parameter \#1 \$stream of function fclose expects resource, resource\|false given\.$#' + identifier: argument.type count: 1 path: src/bundle/IO/BinaryStreamResponse.php - - message: "#^Parameter \\#2 \\$to of function stream_copy_to_stream expects resource, resource\\|false given\\.$#" + message: '#^Parameter \#2 \$to of function stream_copy_to_stream expects resource, resource\|false given\.$#' + identifier: argument.type count: 1 path: src/bundle/IO/BinaryStreamResponse.php - - message: "#^Parameter \\#3 \\$limit of class LimitIterator constructor expects int, int\\|null given\\.$#" + message: '#^Parameter \#3 \$limit of class LimitIterator constructor expects int, int\|null given\.$#' + identifier: argument.type count: 1 path: src/bundle/IO/Migration/FileLister/BinaryFileLister.php - - message: "#^Parameter \\#3 \\$length of function substr expects int\\|null, int\\<0, max\\>\\|false given\\.$#" + message: '#^Parameter \#3 \$length of function substr expects int\|null, int\<0, max\>\|false given\.$#' + identifier: argument.type count: 1 path: src/bundle/IO/Migration/FileLister/FileRowReader/LegacyStorageFileRowReader.php - - message: "#^Parameter \\#3 \\$limit of class LimitIterator constructor expects int, int\\|null given\\.$#" + message: '#^Parameter \#3 \$limit of class LimitIterator constructor expects int, int\|null given\.$#' + identifier: argument.type count: 1 path: src/bundle/IO/Migration/FileLister/ImageFileLister.php - - message: "#^Parameter \\#1 \\$array of function array_keys expects array, array\\|bool\\|float\\|int\\|string\\|null given\\.$#" + message: '#^Parameter \#1 \$array of function array_keys expects array, array\|bool\|float\|int\|string\|null given\.$#' + identifier: argument.type count: 1 path: src/bundle/LegacySearchEngine/ApiLoader/ConnectionFactory.php - - message: "#^Parameter \\#1 \\$object_or_class of function is_a expects object\\|string, string\\|null given\\.$#" + message: '#^Parameter \#1 \$object_or_class of function is_a expects object\|string, string\|null given\.$#' + identifier: argument.type count: 1 path: src/lib/Base/Container/Compiler/FieldTypeRegistryPass.php - - message: "#^Parameter \\#1 \\$object_or_class of function is_subclass_of expects object\\|string, array\\|bool\\|float\\|int\\|string\\|null given\\.$#" + message: '#^Parameter \#1 \$object_or_class of function is_subclass_of expects object\|string, array\|bool\|float\|int\|string\|null given\.$#' + identifier: argument.type count: 1 path: src/lib/Base/Container/Compiler/Storage/ExternalStorageRegistryPass.php - - message: "#^Parameter \\#1 \\$value of function count expects array\\|Countable, array\\|bool\\|float\\|int\\|string\\|null given\\.$#" + message: '#^Parameter \#1 \$value of function count expects array\|Countable, array\|bool\|float\|int\|string\|null given\.$#' + identifier: argument.type count: 1 path: src/lib/FieldType/Author/SearchField.php - - message: "#^Parameter \\#3 \\$length of function substr expects int\\|null, int\\<0, max\\>\\|false given\\.$#" + message: '#^Parameter \#3 \$length of function substr expects int\|null, int\<0, max\>\|false given\.$#' + identifier: argument.type count: 1 path: src/lib/FieldType/BinaryBase/BinaryBaseStorage/Gateway/DoctrineStorage.php - - message: "#^Parameter \\#3 \\$length of function substr expects int\\|null, int\\<0, max\\>\\|false given\\.$#" + message: '#^Parameter \#3 \$length of function substr expects int\|null, int\<0, max\>\|false given\.$#' + identifier: argument.type count: 1 path: src/lib/FieldType/BinaryBase/PathGenerator/LegacyPathGenerator.php - - message: "#^Parameter \\#1 \\.\\.\\.\\$arrays of function array_merge expects array, array\\|bool\\|float\\|int\\|string given\\.$#" + message: '#^Parameter \#1 \.\.\.\$arrays of function array_merge expects array, array\|bool\|float\|int\|string given\.$#' + identifier: argument.type count: 1 path: src/lib/FieldType/Image/ImageStorage.php - - message: "#^Parameter \\#1 \\$array of function array_flip expects array\\, array\\|bool\\|float\\|int\\|string\\|null given\\.$#" + message: '#^Parameter \#1 \$array of function array_flip expects array\, array\|bool\|float\|int\|string\|null given\.$#' + identifier: argument.type count: 1 path: src/lib/FieldType/Selection/SearchField.php - - message: "#^Parameter \\#1 \\$string of function mb_substr expects string, string\\|false given\\.$#" + message: '#^Parameter \#1 \$string of function mb_substr expects string, string\|false given\.$#' + identifier: argument.type count: 1 path: src/lib/FieldType/TextBlock/SearchField.php - - message: "#^Parameter \\#1 \\$string of function mb_substr expects string, string\\|false given\\.$#" + message: '#^Parameter \#1 \$string of function mb_substr expects string, string\|false given\.$#' + identifier: argument.type count: 1 path: src/lib/FieldType/TextBlock/Type.php - - message: "#^Parameter \\#1 \\$array of function array_keys expects array, iterable\\ given\\.$#" + message: '#^Parameter \#1 \$array of function array_keys expects array, iterable\ given\.$#' + identifier: argument.type count: 1 path: src/lib/Limitation/LanguageLimitationType.php - - message: "#^Parameter \\#1 \\$array of function array_keys expects array, iterable\\ given\\.$#" - count: 1 - path: src/lib/MVC/Symfony/FieldType/RelationList/ParameterProvider.php - - - - message: "#^Parameter \\#1 \\.\\.\\.\\$arrays of function array_merge expects array, iterable\\ given\\.$#" + message: '#^Parameter \#1 \.\.\.\$arrays of function array_merge expects array, iterable\ given\.$#' + identifier: argument.type count: 1 path: src/lib/MVC/Symfony/Matcher/ContentBased/UrlAlias.php - - message: "#^Parameter \\#2 \\.\\.\\.\\$arrays of function array_merge expects array, iterable\\ given\\.$#" + message: '#^Parameter \#2 \.\.\.\$arrays of function array_merge expects array, iterable\ given\.$#' + identifier: argument.type count: 1 path: src/lib/MVC/Symfony/Matcher/ContentBased/UrlAlias.php - - message: "#^Parameter \\#2 \\$array of function implode expects array\\|null, array\\|bool\\|float\\|int\\|string given\\.$#" - count: 1 - path: src/lib/Persistence/Legacy/Content/FieldValue/Converter/CountryConverter.php - - - - message: "#^Parameter \\#2 \\$array of function implode expects array\\|null, array\\|float\\|int\\\\|int\\<1, max\\>\\|string\\|true given\\.$#" - count: 1 - path: src/lib/Persistence/Legacy/Content/FieldValue/Converter/CountryConverter.php - - - - message: "#^Parameter \\#1 \\$array of function array_keys expects array, iterable\\ given\\.$#" + message: '#^Parameter \#1 \$array of function array_keys expects array, iterable\ given\.$#' + identifier: argument.type count: 2 path: src/lib/Persistence/Legacy/Content/Language/MaskGenerator.php - - message: "#^Parameter \\#1 \\$string of function strlen expects string, string\\|null given\\.$#" + message: '#^Parameter \#1 \$string of function strlen expects string, string\|null given\.$#' + identifier: argument.type count: 1 path: src/lib/Persistence/TransformationProcessor/DefinitionBased/Parser.php - - message: "#^Parameter \\#1 \\$string of function substr expects string, string\\|null given\\.$#" + message: '#^Parameter \#1 \$string of function substr expects string, string\|null given\.$#' + identifier: argument.type count: 2 path: src/lib/Persistence/TransformationProcessor/DefinitionBased/Parser.php - - message: "#^Parameter \\#2 \\$subject of function preg_match expects string, string\\|null given\\.$#" + message: '#^Parameter \#2 \$subject of function preg_match expects string, string\|null given\.$#' + identifier: argument.type count: 1 path: src/lib/Persistence/TransformationProcessor/DefinitionBased/Parser.php - - message: "#^Parameter \\#1 \\$codepoint of function chr expects int, float\\|int given\\.$#" + message: '#^Parameter \#1 \$codepoint of function chr expects int, float\|int given\.$#' + identifier: argument.type count: 1 path: src/lib/Persistence/TransformationProcessor/PcreCompiler.php - - message: "#^Parameter \\#1 \\$hex_string of function hexdec expects string, string\\|null given\\.$#" + message: '#^Parameter \#1 \$hex_string of function hexdec expects string, string\|null given\.$#' + identifier: argument.type count: 1 path: src/lib/Persistence/TransformationProcessor/PcreCompiler.php - - message: "#^Parameter \\#1 \\$string of function md5 expects string, string\\|false given\\.$#" + message: '#^Parameter \#1 \$string of function md5 expects string, string\|false given\.$#' + identifier: argument.type count: 4 path: src/lib/Repository/Mapper/ContentMapper.php - - message: "#^Parameter \\#1 \\$callback of function spl_autoload_register expects \\(callable\\(string\\)\\: void\\)\\|null, ProxyManager\\\\Autoloader\\\\AutoloaderInterface given\\.$#" + message: '#^Parameter \#1 \$callback of function spl_autoload_register expects \(callable\(string\)\: void\)\|null, ProxyManager\\Autoloader\\AutoloaderInterface given\.$#' + identifier: argument.type count: 1 path: src/lib/Repository/ProxyFactory/ProxyGenerator.php - - message: "#^Parameter \\#1 \\$value of function count expects array\\|Countable, iterable\\ given\\.$#" + message: '#^Parameter \#1 \$value of function count expects array\|Countable, iterable\ given\.$#' + identifier: argument.type count: 1 path: src/lib/Repository/UserService.php - - message: "#^Parameter \\#1 \\$array of function array_keys expects array, string given\\.$#" + message: '#^Parameter \#1 \$array of function array_keys expects array, string given\.$#' + identifier: argument.type count: 3 path: src/lib/Search/Common/FieldNameResolver.php - - message: "#^Parameter \\#1 \\$string of function trim expects string, bool\\|float\\|int\\|string given\\.$#" + message: '#^Parameter \#1 \$string of function trim expects string, bool\|float\|int\|string given\.$#' + identifier: argument.type count: 1 path: src/lib/Search/Legacy/Content/Gateway/CriterionHandler/Ancestor.php - - message: "#^Parameter \\#1 \\$string of function trim expects string, bool\\|float\\|int\\|string given\\.$#" + message: '#^Parameter \#1 \$string of function trim expects string, bool\|float\|int\|string given\.$#' + identifier: argument.type count: 1 path: src/lib/Search/Legacy/Content/Location/Gateway/CriterionHandler/Ancestor.php - - message: "#^Parameter \\#1 \\$value of function count expects array\\|Countable, array\\|bool\\|float\\|int\\|string\\|null given\\.$#" + message: '#^Parameter \#1 \$value of function count expects array\|Countable, array\|bool\|float\|int\|string\|null given\.$#' + identifier: argument.type count: 1 path: tests/bundle/Core/DependencyInjection/IbexaCoreExtensionTest.php - - message: "#^Parameter \\#2 \\.\\.\\.\\$arrays of function array_merge_recursive expects array, array\\|bool\\|float\\|int\\|string\\|null given\\.$#" + message: '#^Parameter \#2 \.\.\.\$arrays of function array_merge_recursive expects array, array\|bool\|float\|int\|string\|null given\.$#' + identifier: argument.type count: 1 path: tests/bundle/Core/DependencyInjection/IbexaCoreExtensionTest.php - - message: "#^Parameter \\#1 \\$string of function trim expects string, string\\|null given\\.$#" + message: '#^Parameter \#1 \$string of function trim expects string, string\|null given\.$#' + identifier: argument.type count: 1 path: tests/bundle/Core/EventListener/BackwardCompatibleCommandListenerTest.php - - message: "#^Parameter \\#2 \\$offset of function substr expects int, int\\<1, max\\>\\|false given\\.$#" + message: '#^Parameter \#2 \$offset of function substr expects int, int\<1, max\>\|false given\.$#' + identifier: argument.type count: 1 path: tests/bundle/Core/EventListener/SiteAccessListenerTest.php - - message: "#^Parameter \\#3 \\$length of function substr expects int\\|null, int\\<0, max\\>\\|false given\\.$#" + message: '#^Parameter \#3 \$length of function substr expects int\|null, int\<0, max\>\|false given\.$#' + identifier: argument.type count: 1 path: tests/bundle/Core/Routing/DefaultRouterTest.php - - message: "#^Parameter \\#1 \\$stream of function fclose expects resource, resource\\|false given\\.$#" + message: '#^Parameter \#1 \$stream of function fclose expects resource, resource\|false given\.$#' + identifier: argument.type count: 1 path: tests/integration/Core/IO/BinarydataHandler/FlysystemTest.php - - message: "#^Parameter \\#1 \\$string1 of function strcmp expects string, bool\\|float\\|int\\|string given\\.$#" + message: '#^Parameter \#1 \$string1 of function strcmp expects string, bool\|float\|int\|string given\.$#' + identifier: argument.type count: 1 path: tests/integration/Core/Repository/BaseTest.php - - message: "#^Parameter \\#2 \\$string2 of function strcmp expects string, bool\\|float\\|int\\|string given\\.$#" + message: '#^Parameter \#2 \$string2 of function strcmp expects string, bool\|float\|int\|string given\.$#' + identifier: argument.type count: 1 path: tests/integration/Core/Repository/BaseTest.php - - message: "#^Parameter \\#1 \\$value of function count expects array\\|Countable, iterable\\ given\\.$#" - count: 4 - path: tests/integration/Core/Repository/ContentServiceAuthorizationTest.php - - - - message: "#^Parameter \\#1 \\$array of function array_keys expects array, iterable\\ given\\.$#" + message: '#^Parameter \#1 \$array of function array_values expects array\, iterable\ given\.$#' + identifier: argument.type count: 1 path: tests/integration/Core/Repository/ContentServiceTest.php - - message: "#^Parameter \\#1 \\$array of function array_values expects array\\, iterable\\ given\\.$#" - count: 1 - path: tests/integration/Core/Repository/ContentServiceTest.php - - - - message: "#^Parameter \\#1 \\$array of function usort expects TArray of array, iterable\\ given\\.$#" - count: 2 - path: tests/integration/Core/Repository/ContentServiceTest.php - - - - message: "#^Parameter \\#1 \\$string of function md5 expects string, float given\\.$#" + message: '#^Parameter \#1 \$string of function md5 expects string, float given\.$#' + identifier: argument.type count: 3 path: tests/integration/Core/Repository/ContentServiceTest.php - - message: "#^Parameter \\#1 \\$value of function count expects array\\|Countable, iterable\\ given\\.$#" - count: 1 - path: tests/integration/Core/Repository/ContentServiceTest.php - - - - message: "#^Parameter \\#1 \\$value of function count expects array\\|Countable, iterable\\ given\\.$#" + message: '#^Parameter \#1 \$value of function count expects array\|Countable, iterable\ given\.$#' + identifier: argument.type count: 1 path: tests/integration/Core/Repository/ContentServiceTest.php - - message: "#^Parameter \\#1 \\$value of function count expects array\\|Countable, iterable\\ given\\.$#" - count: 2 - path: tests/integration/Core/Repository/ContentServiceTest.php - - - - message: "#^Parameter \\#1 \\$value of function count expects array\\|Countable, iterable\\ given\\.$#" + message: '#^Parameter \#1 \$value of function count expects array\|Countable, iterable\ given\.$#' + identifier: argument.type count: 1 path: tests/integration/Core/Repository/ContentTypeServiceTest.php - - message: "#^Parameter \\#1 \\$value of function count expects array\\|Countable, iterable\\ given\\.$#" + message: '#^Parameter \#1 \$value of function count expects array\|Countable, iterable\ given\.$#' + identifier: argument.type count: 1 path: tests/integration/Core/Repository/LanguageServiceMaximumSupportedLanguagesTest.php - - message: "#^Parameter \\#1 \\$value of function count expects array\\|Countable, iterable\\ given\\.$#" + message: '#^Parameter \#1 \$value of function count expects array\|Countable, iterable\ given\.$#' + identifier: argument.type count: 2 path: tests/integration/Core/Repository/LanguageServiceTest.php - - message: "#^Parameter \\#1 \\$array of function array_filter expects array, iterable\\ given\\.$#" + message: '#^Parameter \#1 \$array of function array_filter expects array, iterable\ given\.$#' + identifier: argument.type count: 1 path: tests/integration/Core/Repository/LocationServiceTest.php - - message: "#^Parameter \\#1 \\$array of function array_keys expects array, iterable\\ given\\.$#" + message: '#^Parameter \#1 \$array of function array_keys expects array, iterable\ given\.$#' + identifier: argument.type count: 3 path: tests/integration/Core/Repository/LocationServiceTest.php - - message: "#^Parameter \\#1 \\$array of function array_filter expects array, iterable\\ given\\.$#" + message: '#^Parameter \#1 \$array of function array_filter expects array, iterable\ given\.$#' + identifier: argument.type count: 1 path: tests/integration/Core/Repository/PermissionResolverTest.php - - message: "#^Parameter \\#1 \\$value of function count expects array\\|Countable, iterable\\ given\\.$#" + message: '#^Parameter \#1 \$value of function count expects array\|Countable, iterable\ given\.$#' + identifier: argument.type count: 1 path: tests/integration/Core/Repository/Regression/EZP21798Test.php - - message: "#^Parameter \\#1 \\$value of function count expects array\\|Countable, iterable\\ given\\.$#" + message: '#^Parameter \#1 \$value of function count expects array\|Countable, iterable\ given\.$#' + identifier: argument.type count: 1 path: tests/integration/Core/Repository/RoleServiceTest.php - - message: "#^Parameter \\#1 \\$value of function count expects array\\|Countable, iterable\\ given\\.$#" + message: '#^Parameter \#1 \$value of function count expects array\|Countable, iterable\ given\.$#' + identifier: argument.type count: 3 path: tests/integration/Core/Repository/RoleServiceTest.php - - message: "#^Parameter \\#1 \\.\\.\\.\\$arrays of function array_merge expects array, iterable\\ given\\.$#" + message: '#^Parameter \#1 \.\.\.\$arrays of function array_merge expects array, iterable\ given\.$#' + identifier: argument.type count: 1 path: tests/integration/Core/Repository/RoleServiceTest.php - - message: "#^Parameter \\#1 \\$class of class ReflectionProperty constructor expects object\\|string, class\\-string\\|false given\\.$#" + message: '#^Parameter \#1 \$class of class ReflectionProperty constructor expects object\|string, class\-string\|false given\.$#' + identifier: argument.type count: 4 path: tests/integration/Core/Repository/SearchServiceLocationTest.php - - message: "#^Parameter \\#1 \\$class of class ReflectionProperty constructor expects object\\|string, class\\-string\\|false given\\.$#" + message: '#^Parameter \#1 \$class of class ReflectionProperty constructor expects object\|string, class\-string\|false given\.$#' + identifier: argument.type count: 4 path: tests/integration/Core/Repository/SearchServiceTest.php - - message: "#^Parameter \\#1 \\$string of function md5 expects string, int\\<1, max\\> given\\.$#" + message: '#^Parameter \#1 \$string of function md5 expects string, int\<1, max\> given\.$#' + identifier: argument.type count: 1 path: tests/integration/Core/Repository/Values/User/Limitation/BaseLimitationTest.php - - message: "#^Parameter \\#1 \\$string of function md5 expects string, float given\\.$#" + message: '#^Parameter \#1 \$string of function md5 expects string, float given\.$#' + identifier: argument.type count: 1 path: tests/lib/MVC/Symfony/Security/UserWrappedTest.php - - message: "#^Parameter \\#1 \\$callback of function call_user_func_array expects callable\\(\\)\\: mixed, array\\{mixed, string\\} given\\.$#" + message: '#^Parameter \#1 \$callback of function call_user_func_array expects callable\(\)\: mixed, array\{mixed, string\} given\.$#' + identifier: argument.type count: 3 path: tests/lib/Persistence/Cache/AbstractCacheHandlerTest.php - - message: "#^Parameter \\#1 \\$callback of function call_user_func_array expects callable\\(\\)\\: mixed, array\\{mixed, string\\} given\\.$#" + message: '#^Parameter \#1 \$callback of function call_user_func_array expects callable\(\)\: mixed, array\{mixed, string\} given\.$#' + identifier: argument.type count: 3 path: tests/lib/Persistence/Cache/AbstractInMemoryCacheHandlerTest.php - - message: "#^Parameter \\#1 \\$callback of function call_user_func_array expects callable\\(\\)\\: mixed, array\\{mixed, 'publish'\\} given\\.$#" + message: '#^Parameter \#1 \$callback of function call_user_func_array expects callable\(\)\: mixed, array\{mixed, ''publish''\} given\.$#' + identifier: argument.type count: 1 path: tests/lib/Persistence/Cache/ContentTypeHandlerTest.php - - message: "#^Parameter \\#1 \\.\\.\\.\\$arrays of function array_merge expects array, iterable given\\.$#" + message: '#^Parameter \#1 \.\.\.\$arrays of function array_merge expects array, iterable given\.$#' + identifier: argument.type count: 1 path: tests/lib/Persistence/Legacy/Filter/BaseCriterionVisitorQueryBuilderTestCase.php - - message: "#^Parameter \\#2 \\.\\.\\.\\$arrays of function array_merge expects array, iterable\\ given\\.$#" + message: '#^Parameter \#2 \.\.\.\$arrays of function array_merge expects array, iterable\ given\.$#' + identifier: argument.type count: 1 path: tests/lib/Persistence/Legacy/Filter/BaseCriterionVisitorQueryBuilderTestCase.php - - message: "#^Parameter \\#1 \\$value of function count expects array\\|Countable, iterable\\ given\\.$#" + message: '#^Parameter \#1 \$value of function count expects array\|Countable, iterable\ given\.$#' + identifier: argument.type count: 12 path: tests/lib/Repository/Service/Mock/UrlAliasTest.php - - message: "#^Parameter \\#1 \\$array of function key expects array\\|object, string given\\.$#" + message: '#^Parameter \#1 \$array of function key expects array\|object, string given\.$#' + identifier: argument.type count: 4 path: tests/lib/Search/FieldNameResolverTest.php diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 1fca190834..e6267c56ce 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -276,12 +276,6 @@ parameters: count: 1 path: src/bundle/Core/Command/RegenerateUrlAliasesCommand.php - - - message: '#^Cannot access offset int on iterable\\.$#' - identifier: offsetAccess.nonOffsetAccessible - count: 1 - path: src/bundle/Core/Command/RegenerateUrlAliasesCommand.php - - message: '#^Method Ibexa\\Bundle\\Core\\Command\\RegenerateUrlAliasesCommand\:\:configure\(\) has no return type specified\.$#' identifier: missingType.return @@ -1080,12 +1074,6 @@ parameters: count: 1 path: src/bundle/Core/DependencyInjection/Configuration/ConfigResolver.php - - - message: '#^Offset ''function'' on array\{function\: string, line\?\: int, file\?\: string, class\?\: class\-string, type\?\: ''\-\>''\|''\:\:'', args\?\: array\, object\?\: object\} in isset\(\) always exists and is not nullable\.$#' - identifier: isset.offset - count: 1 - path: src/bundle/Core/DependencyInjection/Configuration/ConfigResolver.php - - message: '#^Parameter \#2 \$haystack of function in_array expects array, array\|bool\|float\|int\|string\|null given\.$#' identifier: argument.type @@ -10290,12 +10278,6 @@ parameters: count: 1 path: src/lib/Base/Utils/DeprecationWarnerInterface.php - - - message: '#^Parameter \#1 \$locations of class Ibexa\\Contracts\\Core\\Repository\\Events\\Content\\DeleteContentEvent constructor expects array, array\|iterable\ given\.$#' - identifier: argument.type - count: 1 - path: src/lib/Event/ContentService.php - - message: '#^Method Ibexa\\Core\\Event\\TokenService\:\:getToken\(\) should return Ibexa\\Contracts\\Core\\Repository\\Values\\Token\\Token but returns Ibexa\\Contracts\\Core\\Repository\\Values\\Token\\Token\|string\.$#' identifier: return.type @@ -10734,12 +10716,6 @@ parameters: count: 1 path: src/lib/FieldType/BinaryFile/Type.php - - - message: '#^Method Ibexa\\Core\\FieldType\\BinaryFile\\Type\:\:completeValue\(\) has no return type specified\.$#' - identifier: missingType.return - count: 1 - path: src/lib/FieldType/BinaryFile/Type.php - - message: '#^Method Ibexa\\Core\\FieldType\\BinaryFile\\Type\:\:createValue\(\) has parameter \$inputValue with no value type specified in iterable type array\.$#' identifier: missingType.iterableValue @@ -11898,12 +11874,6 @@ parameters: count: 1 path: src/lib/FieldType/Media/Type.php - - - message: '#^Method Ibexa\\Core\\FieldType\\Media\\Type\:\:completeValue\(\) has no return type specified\.$#' - identifier: missingType.return - count: 1 - path: src/lib/FieldType/Media/Type.php - - message: '#^Method Ibexa\\Core\\FieldType\\Media\\Type\:\:createValue\(\) has parameter \$inputValue with no value type specified in iterable type array\.$#' identifier: missingType.iterableValue @@ -17616,12 +17586,6 @@ parameters: count: 1 path: src/lib/Persistence/Cache/PersistenceLogger.php - - - message: '#^Offset ''class'' might not exist on array\{function\: string, line\?\: int, file\?\: string, class\?\: class\-string, type\?\: ''\-\>''\|''\:\:'', args\?\: array\, object\?\: object\}\.$#' - identifier: offsetAccess.notFound - count: 2 - path: src/lib/Persistence/Cache/PersistenceLogger.php - - message: '#^Property Ibexa\\Core\\Persistence\\Cache\\PersistenceLogger\:\:\$calls type has no value type specified in iterable type array\.$#' identifier: missingType.iterableValue @@ -18498,12 +18462,6 @@ parameters: count: 1 path: src/lib/Persistence/Legacy/Content/FieldValue/Converter/ImageConverter.php - - - message: '#^Cannot access property \$nodeValue on \(TNode of DOMNode\)\|null\.$#' - identifier: property.nonObject - count: 1 - path: src/lib/Persistence/Legacy/Content/FieldValue/Converter/ImageConverter.php - - message: '#^Cannot call method getAttribute\(\) on DOMElement\|null\.$#' identifier: method.nonObject @@ -33084,72 +33042,12 @@ parameters: count: 7 path: tests/integration/Core/Repository/ContentServiceTest.php - - - message: '#^Cannot access offset 0 on iterable\\.$#' - identifier: offsetAccess.nonOffsetAccessible - count: 12 - path: tests/integration/Core/Repository/ContentServiceTest.php - - - - message: '#^Cannot access offset 0 on iterable\\.$#' - identifier: offsetAccess.nonOffsetAccessible - count: 4 - path: tests/integration/Core/Repository/ContentServiceTest.php - - message: '#^Cannot access offset 1 on iterable\\.$#' identifier: offsetAccess.nonOffsetAccessible count: 2 path: tests/integration/Core/Repository/ContentServiceTest.php - - - message: '#^Cannot access offset 1 on iterable\\.$#' - identifier: offsetAccess.nonOffsetAccessible - count: 4 - path: tests/integration/Core/Repository/ContentServiceTest.php - - - - message: '#^Cannot access offset 1 on iterable\\.$#' - identifier: offsetAccess.nonOffsetAccessible - count: 1 - path: tests/integration/Core/Repository/ContentServiceTest.php - - - - message: '#^Cannot access offset 2 on iterable\\.$#' - identifier: offsetAccess.nonOffsetAccessible - count: 1 - path: tests/integration/Core/Repository/ContentServiceTest.php - - - - message: '#^Cannot access offset 3 on iterable\\.$#' - identifier: offsetAccess.nonOffsetAccessible - count: 1 - path: tests/integration/Core/Repository/ContentServiceTest.php - - - - message: '#^Cannot access offset 4 on iterable\\.$#' - identifier: offsetAccess.nonOffsetAccessible - count: 1 - path: tests/integration/Core/Repository/ContentServiceTest.php - - - - message: '#^Cannot access offset 5 on iterable\\.$#' - identifier: offsetAccess.nonOffsetAccessible - count: 2 - path: tests/integration/Core/Repository/ContentServiceTest.php - - - - message: '#^Cannot access offset int on iterable\\.$#' - identifier: offsetAccess.nonOffsetAccessible - count: 1 - path: tests/integration/Core/Repository/ContentServiceTest.php - - - - message: '#^Cannot access offset mixed on iterable\\.$#' - identifier: offsetAccess.nonOffsetAccessible - count: 1 - path: tests/integration/Core/Repository/ContentServiceTest.php - - message: '#^Cannot access property \$sortField on Ibexa\\Contracts\\Core\\Repository\\Values\\Content\\Location\|null\.$#' identifier: property.nonObject @@ -33252,12 +33150,6 @@ parameters: count: 1 path: tests/integration/Core/Repository/ContentServiceTest.php - - - message: '#^Method Ibexa\\Tests\\Integration\\Core\\Repository\\ContentServiceTest\:\:testAddRelation\(\) should return array\ but returns iterable\\.$#' - identifier: return.type - count: 1 - path: tests/integration/Core/Repository/ContentServiceTest.php - - message: '#^Method Ibexa\\Tests\\Integration\\Core\\Repository\\ContentServiceTest\:\:testAddRelationAddsRelationToContent\(\) has no return type specified\.$#' identifier: missingType.return @@ -33390,12 +33282,6 @@ parameters: count: 1 path: tests/integration/Core/Repository/ContentServiceTest.php - - - message: '#^Method Ibexa\\Tests\\Integration\\Core\\Repository\\ContentServiceTest\:\:testCreateContentDraftWithRelations\(\) should return array\ but returns iterable\\.$#' - identifier: return.type - count: 1 - path: tests/integration/Core/Repository/ContentServiceTest.php - - message: '#^Method Ibexa\\Tests\\Integration\\Core\\Repository\\ContentServiceTest\:\:testCreateContentDraftWithRelationsCreatesExpectedRelations\(\) has no return type specified\.$#' identifier: missingType.return @@ -33990,12 +33876,6 @@ parameters: count: 1 path: tests/integration/Core/Repository/ContentServiceTest.php - - - message: '#^Method Ibexa\\Tests\\Integration\\Core\\Repository\\ContentServiceTest\:\:testLoadVersions\(\) should return array\ but returns iterable\\.$#' - identifier: return.type - count: 1 - path: tests/integration/Core/Repository/ContentServiceTest.php - - message: '#^Method Ibexa\\Tests\\Integration\\Core\\Repository\\ContentServiceTest\:\:testLoadVersionsAfterDeletingTwoDrafts\(\) has no return type specified\.$#' identifier: missingType.return @@ -37482,18 +37362,6 @@ parameters: count: 1 path: tests/integration/Core/Repository/FieldType/RelationIntegrationTest.php - - - message: '#^Parameter \#1 \$relations of method Ibexa\\Tests\\Integration\\Core\\Repository\\FieldType\\RelationIntegrationTest\:\:normalizeRelations\(\) expects array\, array\ given\.$#' - identifier: argument.type - count: 5 - path: tests/integration/Core/Repository/FieldType/RelationIntegrationTest.php - - - - message: '#^Parameter \#1 \$relations of method Ibexa\\Tests\\Integration\\Core\\Repository\\FieldType\\RelationIntegrationTest\:\:normalizeRelations\(\) expects array\, iterable\ given\.$#' - identifier: argument.type - count: 5 - path: tests/integration/Core/Repository/FieldType/RelationIntegrationTest.php - - message: '#^Method Ibexa\\Tests\\Integration\\Core\\Repository\\FieldType\\RelationListIntegrationTest\:\:assertCopiedFieldDataLoadedCorrectly\(\) has no return type specified\.$#' identifier: missingType.return @@ -37602,18 +37470,6 @@ parameters: count: 1 path: tests/integration/Core/Repository/FieldType/RelationListIntegrationTest.php - - - message: '#^Parameter \#1 \$relations of method Ibexa\\Tests\\Integration\\Core\\Repository\\FieldType\\RelationListIntegrationTest\:\:normalizeRelations\(\) expects array\, array\ given\.$#' - identifier: argument.type - count: 5 - path: tests/integration/Core/Repository/FieldType/RelationListIntegrationTest.php - - - - message: '#^Parameter \#1 \$relations of method Ibexa\\Tests\\Integration\\Core\\Repository\\FieldType\\RelationListIntegrationTest\:\:normalizeRelations\(\) expects array\, iterable\ given\.$#' - identifier: argument.type - count: 5 - path: tests/integration/Core/Repository/FieldType/RelationListIntegrationTest.php - - message: '#^Method Ibexa\\Tests\\Integration\\Core\\Repository\\FieldType\\SearchBaseIntegrationTest\:\:assertFindResult\(\) has no return type specified\.$#' identifier: missingType.return @@ -60534,42 +60390,12 @@ parameters: count: 1 path: tests/lib/Persistence/Cache/PersistenceLoggerTest.php - - - message: '#^Method Ibexa\\Tests\\Core\\Persistence\\Cache\\PersistenceLoggerTest\:\:testGetCalls\(\) has no return type specified\.$#' - identifier: missingType.return - count: 1 - path: tests/lib/Persistence/Cache/PersistenceLoggerTest.php - - - - message: '#^Method Ibexa\\Tests\\Core\\Persistence\\Cache\\PersistenceLoggerTest\:\:testGetCount\(\) has no return type specified\.$#' - identifier: missingType.return - count: 1 - path: tests/lib/Persistence/Cache/PersistenceLoggerTest.php - - message: '#^Method Ibexa\\Tests\\Core\\Persistence\\Cache\\PersistenceLoggerTest\:\:testGetCountValues\(\) has no return type specified\.$#' identifier: missingType.return count: 1 path: tests/lib/Persistence/Cache/PersistenceLoggerTest.php - - - message: '#^Method Ibexa\\Tests\\Core\\Persistence\\Cache\\PersistenceLoggerTest\:\:testGetName\(\) has no return type specified\.$#' - identifier: missingType.return - count: 1 - path: tests/lib/Persistence/Cache/PersistenceLoggerTest.php - - - - message: '#^Method Ibexa\\Tests\\Core\\Persistence\\Cache\\PersistenceLoggerTest\:\:testLogCall\(\) has no return type specified\.$#' - identifier: missingType.return - count: 1 - path: tests/lib/Persistence/Cache/PersistenceLoggerTest.php - - - - message: '#^Result of method Ibexa\\Core\\Persistence\\Cache\\PersistenceLogger\:\:logCall\(\) \(void\) is used\.$#' - identifier: method.void - count: 1 - path: tests/lib/Persistence/Cache/PersistenceLoggerTest.php - - message: '#^Method Ibexa\\Tests\\Core\\Persistence\\Cache\\SectionHandlerTest\:\:providerForCachedLoadMethodsHit\(\) return type has no value type specified in iterable type array\.$#' identifier: missingType.iterableValue @@ -63798,12 +63624,6 @@ parameters: count: 1 path: tests/lib/Persistence/Legacy/Content/MapperTest.php - - - message: '#^Possibly invalid array key type \(list\\|string\)\.$#' - identifier: offsetAccess.invalidOffset - count: 2 - path: tests/lib/Persistence/Legacy/Content/MapperTest.php - - message: '#^Property Ibexa\\Contracts\\Core\\Persistence\\Content\\CreateStruct\:\:\$name \(array\\) does not accept string\.$#' identifier: assign.propertyType diff --git a/src/bundle/Core/DependencyInjection/Configuration/ConfigResolver.php b/src/bundle/Core/DependencyInjection/Configuration/ConfigResolver.php index 2b4d4a194b..555dc1b7a8 100644 --- a/src/bundle/Core/DependencyInjection/Configuration/ConfigResolver.php +++ b/src/bundle/Core/DependencyInjection/Configuration/ConfigResolver.php @@ -279,7 +279,7 @@ private function logTooEarlyLoadedListIfNeeded($paramName) // Lookup trace to find last service being loaded as possible blame for eager loading // Abort if one of the earlier services is detected to be "safe", aka updatable foreach (debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 35) as $t) { - if (!isset($t['function']) || $t['function'] === 'getParameter' || $t['function'] === __FUNCTION__) { + if ($t['function'] === 'getParameter' || $t['function'] === __FUNCTION__) { continue; } diff --git a/src/lib/FieldType/BinaryFile/Type.php b/src/lib/FieldType/BinaryFile/Type.php index c14a35e070..e0d6f582e6 100644 --- a/src/lib/FieldType/BinaryFile/Type.php +++ b/src/lib/FieldType/BinaryFile/Type.php @@ -9,7 +9,6 @@ use Ibexa\Contracts\Core\FieldType\Value as SPIValue; use Ibexa\Contracts\Core\Persistence\Content\FieldValue; use Ibexa\Core\FieldType\BinaryBase\Type as BinaryBaseType; -use Ibexa\Core\FieldType\Value as BaseValue; use JMS\TranslationBundle\Model\Message; use JMS\TranslationBundle\Translation\TranslationContainerInterface; @@ -55,20 +54,6 @@ protected function createValue(array $inputValue) return new Value($inputValue); } - /** - * Attempts to complete the data in $value. - * - * @param \Ibexa\Core\FieldType\BinaryFile\Value|\Ibexa\Core\FieldType\Value $value - */ - protected function completeValue(Basevalue $value) - { - parent::completeValue($value); - - if (isset($value->downloadCount) && $value->downloadCount === null) { - $value->downloadCount = 0; - } - } - /** * Converts a $Value to a hash. * diff --git a/src/lib/FieldType/Media/Type.php b/src/lib/FieldType/Media/Type.php index c416bf0cd7..9353d5837c 100644 --- a/src/lib/FieldType/Media/Type.php +++ b/src/lib/FieldType/Media/Type.php @@ -180,33 +180,6 @@ protected function checkValueStructure(BaseValue $value) } } - /** - * Attempts to complete the data in $value. - * - * @param \Ibexa\Core\FieldType\Media\Value|\Ibexa\Core\FieldType\Value $value - */ - protected function completeValue(BaseValue $value) - { - parent::completeValue($value); - - if (isset($value->hasController) && $value->hasController === null) { - $value->hasController = false; - } - if (isset($value->autoplay) && $value->autoplay === null) { - $value->autoplay = false; - } - if (isset($value->loop) && $value->loop === null) { - $value->loop = false; - } - - if (isset($value->height) && $value->height === null) { - $value->height = 0; - } - if (isset($value->width) && $value->width === null) { - $value->width = 0; - } - } - /** * Converts a $Value to a hash. * diff --git a/src/lib/MVC/Symfony/View/Provider/Registry.php b/src/lib/MVC/Symfony/View/Provider/Registry.php index 6565514840..fcb53b8c7a 100644 --- a/src/lib/MVC/Symfony/View/Provider/Registry.php +++ b/src/lib/MVC/Symfony/View/Provider/Registry.php @@ -14,7 +14,7 @@ class Registry /** * Array of ViewProvider, indexed by handled type. * - * @var \Ibexa\Core\MVC\Symfony\View\ViewProvider[][] + * @phpstan-var array> */ private $viewProviders; diff --git a/src/lib/Persistence/Cache/PersistenceLogger.php b/src/lib/Persistence/Cache/PersistenceLogger.php index 53da8fbb47..a9c8307a2d 100644 --- a/src/lib/Persistence/Cache/PersistenceLogger.php +++ b/src/lib/Persistence/Cache/PersistenceLogger.php @@ -85,7 +85,7 @@ public function logCacheMiss(array $arguments = [], int $traceOffset = 2): void $trace = \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 8 + $traceOffset); $this->collectCacheCallData( - $trace[$traceOffset - 1]['class'] . '::' . $trace[$traceOffset - 1]['function'], + $this->resolveTraceFrameName($trace[$traceOffset - 1]), $arguments, \array_slice($trace, $traceOffset), 'miss' @@ -116,7 +116,7 @@ public function logCacheHit(array $arguments = [], int $traceOffset = 2, bool $i $trace = \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 8 + $traceOffset); $this->collectCacheCallData( - $trace[$traceOffset - 1]['class'] . '::' . $trace[$traceOffset - 1]['function'], + $this->resolveTraceFrameName($trace[$traceOffset - 1]), $arguments, \array_slice($trace, $traceOffset), $inMemory ? 'memory' : 'hit' @@ -249,6 +249,18 @@ public function getLoadedUnCachedHandlers(): array { return $this->unCachedHandlers; } + + /** + * @param array{class?: string, function: string} $traceFrame + */ + private function resolveTraceFrameName(array $traceFrame): string + { + $classNameWithScopeResolution = isset($traceFrame['class']) + ? $traceFrame['class'] . '::' + : ''; + + return $classNameWithScopeResolution . $traceFrame['function']; + } } class_alias(PersistenceLogger::class, 'eZ\Publish\Core\Persistence\Cache\PersistenceLogger'); diff --git a/src/lib/Persistence/Legacy/Content/FieldValue/Converter/CountryConverter.php b/src/lib/Persistence/Legacy/Content/FieldValue/Converter/CountryConverter.php index 670839dddb..733c21bcc9 100644 --- a/src/lib/Persistence/Legacy/Content/FieldValue/Converter/CountryConverter.php +++ b/src/lib/Persistence/Legacy/Content/FieldValue/Converter/CountryConverter.php @@ -37,7 +37,9 @@ public static function create() */ public function toStorageValue(FieldValue $value, StorageFieldValue $storageFieldValue) { - $storageFieldValue->dataText = empty($value->data) ? '' : implode(',', $value->data); + $storageFieldValue->dataText = empty($value->data) || !is_array($value->data) + ? '' + : implode(',', $value->data); $storageFieldValue->sortKeyString = $value->sortKey; } @@ -65,7 +67,7 @@ public function toStorageFieldDefinition(FieldDefinition $fieldDef, StorageField $storageDef->dataInt1 = (int)$fieldDef->fieldTypeConstraints->fieldSettings['isMultiple']; } - $storageDef->dataText5 = $fieldDef->defaultValue->data === null + $storageDef->dataText5 = $fieldDef->defaultValue->data === null || !is_array($fieldDef->defaultValue->data) ? '' : implode(',', $fieldDef->defaultValue->data); } diff --git a/src/lib/Persistence/Legacy/Content/FieldValue/Converter/ImageConverter.php b/src/lib/Persistence/Legacy/Content/FieldValue/Converter/ImageConverter.php index 3b30bd924a..2159b03bc8 100644 --- a/src/lib/Persistence/Legacy/Content/FieldValue/Converter/ImageConverter.php +++ b/src/lib/Persistence/Legacy/Content/FieldValue/Converter/ImageConverter.php @@ -13,6 +13,7 @@ use Ibexa\Core\IO\UrlRedecoratorInterface; use Ibexa\Core\Persistence\Legacy\Content\StorageFieldDefinition; use Ibexa\Core\Persistence\Legacy\Content\StorageFieldValue; +use LogicException; use SimpleXMLElement; class ImageConverter extends BinaryFileConverter @@ -277,7 +278,13 @@ protected function parseLegacyXml($xml) foreach ($additionalDataElement->getElementsByTagName('attribute') as $datum) { /** @var \DOMNamedNodeMap $option */ $option = $datum->attributes; - $extractedData['additionalData'][$option->getNamedItem('key')->nodeValue] = $datum->nodeValue; + $domNode = $option->getNamedItem('key'); + if (null === $domNode) { + throw new LogicException( + sprintf('ImageConverter: Failed to get "%s" key from "%s" node', 'key', $datum->getNodePath()) + ); + } + $extractedData['additionalData'][$domNode->nodeValue] = $datum->nodeValue; } } diff --git a/tests/integration/Core/Repository/FieldType/RelationSearchBaseIntegrationTestTrait.php b/tests/integration/Core/Repository/FieldType/RelationSearchBaseIntegrationTestTrait.php index 161799afb9..f4b258043b 100644 --- a/tests/integration/Core/Repository/FieldType/RelationSearchBaseIntegrationTestTrait.php +++ b/tests/integration/Core/Repository/FieldType/RelationSearchBaseIntegrationTestTrait.php @@ -8,6 +8,7 @@ use Ibexa\Contracts\Core\Repository\Values\Content\Content; use Ibexa\Contracts\Core\Repository\Values\Content\LocationCreateStruct; +use Ibexa\Contracts\Core\Repository\Values\Content\Relation as APIRelation; use Ibexa\Core\Repository\Values\Content\Relation; /** @@ -72,25 +73,26 @@ public function testUpdateContentRelationsProcessedCorrect() /** * Normalizes given $relations for easier comparison. * - * @param \Ibexa\Core\Repository\Values\Content\Relation[] $relations + * @param \Ibexa\Contracts\Core\Repository\Values\Content\Relation[] $relations * - * @return \Ibexa\Core\Repository\Values\Content\Relation[] + * @return \Ibexa\Contracts\Core\Repository\Values\Content\Relation[] */ - protected function normalizeRelations(array $relations) + protected function normalizeRelations(array $relations): array { usort( $relations, - static function (Relation $a, Relation $b) { - if ($a->type == $b->type) { + static function (APIRelation $a, APIRelation $b): int { + if ($a->type === $b->type) { return $a->destinationContentInfo->id < $b->destinationContentInfo->id ? 1 : -1; } return $a->type < $b->type ? 1 : -1; } ); - $normalized = array_map( - static function (Relation $relation) { - $newRelation = new Relation( + + return array_map( + static function (APIRelation $relation): APIRelation { + return new Relation( [ 'id' => null, 'sourceFieldDefinitionIdentifier' => $relation->sourceFieldDefinitionIdentifier, @@ -99,13 +101,9 @@ static function (Relation $relation) { 'destinationContentInfo' => $relation->destinationContentInfo, ] ); - - return $newRelation; }, $relations ); - - return $normalized; } public function testCopyContentCopiesFieldRelations() diff --git a/tests/lib/Persistence/Cache/PersistenceLoggerTest.php b/tests/lib/Persistence/Cache/PersistenceLoggerTest.php index 23eda2909d..e29ec7a5dd 100644 --- a/tests/lib/Persistence/Cache/PersistenceLoggerTest.php +++ b/tests/lib/Persistence/Cache/PersistenceLoggerTest.php @@ -4,55 +4,50 @@ * @copyright Copyright (C) Ibexa AS. All rights reserved. * @license For full copyright and license information view LICENSE file distributed with this source code. */ +declare(strict_types=1); + namespace Ibexa\Tests\Core\Persistence\Cache; use Ibexa\Core\Persistence\Cache\PersistenceLogger; use PHPUnit\Framework\TestCase; /** - * @covers \Ibexa\Core\Persistence\Cache\PersistenceLogger::getName + * @covers \Ibexa\Core\Persistence\Cache\PersistenceLogger */ class PersistenceLoggerTest extends TestCase { - /** @var \Ibexa\Core\Persistence\Cache\PersistenceLogger */ - protected $logger; + protected PersistenceLogger $logger; - /** - * Setup the HandlerTest. - */ protected function setUp(): void { parent::setUp(); $this->logger = new PersistenceLogger(); } - /** - * Tear down test (properties). - */ protected function tearDown(): void { unset($this->logger); parent::tearDown(); } - public function testGetName() + public function testGetName(): void { $this->assertEquals(PersistenceLogger::NAME, $this->logger->getName()); } - public function testGetCount() + public function testGetCount(): void { $this->assertEquals(0, $this->logger->getCount()); } - public function testGetCalls() + public function testGetCalls(): void { $this->assertEquals([], $this->logger->getCalls()); } - public function testLogCall() + public function testLogCall(): PersistenceLogger { - $this->assertNull($this->logger->logCall(__METHOD__)); + $this->logger->logCall(__METHOD__); $this->logger->logCall(__METHOD__); $this->logger->logCall(__METHOD__); $this->logger->logCall(__METHOD__, [33]); @@ -95,6 +90,54 @@ public function testGetCallValues($logger) $this->assertCount(1, $calls[1]['traces']); $this->assertEquals(['uncached' => 1, 'miss' => 0, 'hit' => 0, 'memory' => 0], $calls[1]['stats']); } + + public function testLogCacheHit(): void + { + self::assertSame([], $this->logger->getCalls()); + $this->logger->logCacheHit(); + self::assertSame( + $this->buildExpectedCallTrace('d4371e7c', __METHOD__, 0, 1), + $this->logger->getCalls() + ); + } + + public function testLogCacheMiss(): void + { + self::assertSame([], $this->logger->getCalls()); + $this->logger->logCacheMiss(); + self::assertSame( + $this->buildExpectedCallTrace('f4051ef3', __METHOD__, 1, 0), + $this->logger->getCalls() + ); + } + + /** + * @return array> + */ + private function buildExpectedCallTrace(string $callHash, string $method, int $miss, int $hit): array + { + return [ + $callHash => [ + 'method' => $method, + 'arguments' => [], + 'stats' => [ + 'uncached' => 0, + 'miss' => $miss, + 'hit' => $hit, + 'memory' => 0, + ], + 'traces' => [ + '0e1c1b51' => [ + 'trace' => [ + 0 => 'PHPUnit\\Framework\\TestCase->runTest()', + 1 => 'PHPUnit\\Framework\\TestCase->runBare()', + ], + 'count' => 1, + ], + ], + ], + ]; + } } class_alias(PersistenceLoggerTest::class, 'eZ\Publish\Core\Persistence\Cache\Tests\PersistenceLoggerTest'); diff --git a/tests/lib/Repository/Values/Translation/MessageTest.php b/tests/lib/Repository/Values/Translation/MessageTest.php index 278847cb4b..757158e2e0 100644 --- a/tests/lib/Repository/Values/Translation/MessageTest.php +++ b/tests/lib/Repository/Values/Translation/MessageTest.php @@ -25,7 +25,7 @@ public function testStringable(Message $message, string $expectedString): void } /** - * @return array + * @return iterable */ public static function getDataForTestStringable(): iterable { diff --git a/tests/lib/Repository/Values/Translation/PluralTest.php b/tests/lib/Repository/Values/Translation/PluralTest.php index d0d6e57f96..b1158f0cf7 100644 --- a/tests/lib/Repository/Values/Translation/PluralTest.php +++ b/tests/lib/Repository/Values/Translation/PluralTest.php @@ -25,7 +25,7 @@ public function testStringable(Plural $message, string $expectedString): void } /** - * @return array + * @return iterable */ public static function getDataForTestStringable(): iterable { From db39fd7746e1ffe8f5c3f920899bf5ad28ebc37a Mon Sep 17 00:00:00 2001 From: Andrew Longosz Date: Fri, 12 Sep 2025 00:23:31 +0200 Subject: [PATCH 2/3] Fixed the incorrect type hint for `CreateStruct::$mainLocationId` (#648) For more details see https://github.com/ibexa/core/pull/648 Key changes: * Fixed the incorrect type hint for `CreateStruct::$mainLocationId` * Ensured values assigned to `CreateStruct::$mainLocationId` are of the correct type * Fixed PHPDoc of the related `Location\Gateway::create` method * [PHPStan] Regenerated baseline after the changes --- phpstan-baseline.neon | 18 ------------------ .../Content/Location/CreateStruct.php | 2 +- .../Legacy/Content/Location/Gateway.php | 4 ++-- .../Location/Gateway/DoctrineDatabase.php | 2 +- .../Legacy/Content/Location/Handler.php | 2 +- .../Legacy/Content/Location/Mapper.php | 2 +- 6 files changed, 6 insertions(+), 24 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index e6267c56ce..a49ab96840 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -19674,12 +19674,6 @@ parameters: count: 1 path: src/lib/Persistence/Legacy/Content/Language/MaskGenerator.php - - - message: '#^Method Ibexa\\Core\\Persistence\\Legacy\\Content\\Location\\Gateway\:\:create\(\) has parameter \$parentNode with no value type specified in iterable type array\.$#' - identifier: missingType.iterableValue - count: 1 - path: src/lib/Persistence/Legacy/Content/Location/Gateway.php - - message: '#^Method Ibexa\\Core\\Persistence\\Legacy\\Content\\Location\\Gateway\:\:getBasicNodeData\(\) return type has no value type specified in iterable type array\.$#' identifier: missingType.iterableValue @@ -19788,12 +19782,6 @@ parameters: count: 1 path: src/lib/Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php - - - message: '#^Method Ibexa\\Core\\Persistence\\Legacy\\Content\\Location\\Gateway\\DoctrineDatabase\:\:create\(\) has parameter \$parentNode with no value type specified in iterable type array\.$#' - identifier: missingType.iterableValue - count: 1 - path: src/lib/Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php - - message: '#^Method Ibexa\\Core\\Persistence\\Legacy\\Content\\Location\\Gateway\\DoctrineDatabase\:\:createNodeQueryBuilder\(\) has parameter \$columns with no value type specified in iterable type array\.$#' identifier: missingType.iterableValue @@ -19956,12 +19944,6 @@ parameters: count: 8 path: src/lib/Persistence/Legacy/Content/Location/Gateway/ExceptionConversion.php - - - message: '#^Method Ibexa\\Core\\Persistence\\Legacy\\Content\\Location\\Gateway\\ExceptionConversion\:\:create\(\) has parameter \$parentNode with no value type specified in iterable type array\.$#' - identifier: missingType.iterableValue - count: 1 - path: src/lib/Persistence/Legacy/Content/Location/Gateway/ExceptionConversion.php - - message: '#^Method Ibexa\\Core\\Persistence\\Legacy\\Content\\Location\\Gateway\\ExceptionConversion\:\:getBasicNodeData\(\) return type has no value type specified in iterable type array\.$#' identifier: missingType.iterableValue diff --git a/src/contracts/Persistence/Content/Location/CreateStruct.php b/src/contracts/Persistence/Content/Location/CreateStruct.php index 0796c1b840..1484b79484 100644 --- a/src/contracts/Persistence/Content/Location/CreateStruct.php +++ b/src/contracts/Persistence/Content/Location/CreateStruct.php @@ -83,7 +83,7 @@ class CreateStruct extends ValueObject * This is allowed to be set to true, this will mean this should become main location * (@todo Find a better way to deal with being able to create the main location) * - * @var mixed|true + * @var int|true */ public $mainLocationId = true; diff --git a/src/lib/Persistence/Legacy/Content/Location/Gateway.php b/src/lib/Persistence/Legacy/Content/Location/Gateway.php index d67f3fe46d..90194e2cf8 100644 --- a/src/lib/Persistence/Legacy/Content/Location/Gateway.php +++ b/src/lib/Persistence/Legacy/Content/Location/Gateway.php @@ -209,9 +209,9 @@ abstract public function setNodeUnhidden(string $pathString): void; abstract public function swap(int $locationId1, int $locationId2): bool; /** - * Creates a new location in given $parentNode. + * Creates a new location in the given `$parentNode`. * - * @param array $parentNode parent node raw data + * @param array $parentNode parent node raw data */ abstract public function create(CreateStruct $createStruct, array $parentNode): Location; diff --git a/src/lib/Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php b/src/lib/Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php index d1c0ea4a8a..c3fae3f5fe 100644 --- a/src/lib/Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php +++ b/src/lib/Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php @@ -778,7 +778,7 @@ public function create(CreateStruct $createStruct, array $parentNode): Location { $location = $this->insertLocationIntoContentTree($createStruct, $parentNode); - $mainLocationId = $createStruct->mainLocationId === true ? $location->id : $createStruct->mainLocationId; + $mainLocationId = $createStruct->mainLocationId === true ? $location->id : (int)$createStruct->mainLocationId; $location->pathString = $parentNode['path_string'] . $location->id . '/'; $query = $this->connection->createQueryBuilder(); $query diff --git a/src/lib/Persistence/Legacy/Content/Location/Handler.php b/src/lib/Persistence/Legacy/Content/Location/Handler.php index 9c69f5a670..9cd1080a86 100644 --- a/src/lib/Persistence/Legacy/Content/Location/Handler.php +++ b/src/lib/Persistence/Legacy/Content/Location/Handler.php @@ -285,7 +285,7 @@ public function copySubtree($sourceId, $destinationParentId, $newOwnerId = null) // Use content main location if already set, otherwise create location as main if (isset($mainLocations[$child['contentobject_id']])) { - $createStruct->mainLocationId = $locationMap[$mainLocations[$child['contentobject_id']]]['id']; + $createStruct->mainLocationId = (int)$locationMap[$mainLocations[$child['contentobject_id']]]['id']; } else { $createStruct->mainLocationId = true; $mainLocations[$child['contentobject_id']] = $child['node_id']; diff --git a/src/lib/Persistence/Legacy/Content/Location/Mapper.php b/src/lib/Persistence/Legacy/Content/Location/Mapper.php index 4afeb7109e..9ca584204b 100644 --- a/src/lib/Persistence/Legacy/Content/Location/Mapper.php +++ b/src/lib/Persistence/Legacy/Content/Location/Mapper.php @@ -89,7 +89,7 @@ public function getLocationCreateStruct(array $data) $struct->contentVersion = $data['contentobject_version']; $struct->hidden = $data['is_hidden']; $struct->invisible = $data['is_invisible']; - $struct->mainLocationId = $data['main_node_id']; + $struct->mainLocationId = (int)$data['main_node_id']; $struct->parentId = $data['parent_node_id']; $struct->pathIdentificationString = $data['path_identification_string']; $struct->priority = $data['priority']; From ea58659e5483473a202a6299868e209e2adf62c9 Mon Sep 17 00:00:00 2001 From: Vidar Langseid Date: Fri, 12 Sep 2025 01:33:21 +0200 Subject: [PATCH 3/3] IBX-9446: Fixed updating new non-translatable field value (#533) For more details see https://issues.ibexa.co/browse/IBX-9446 and https://github.com/ibexa/core/pull/533 Key changes: * Fixed processing update of a non-translatable field newly added to a content type --- .../Legacy/Content/FieldHandler.php | 2 +- ...ntUpdateAfterAddingFieldDefinitionTest.php | 149 ++++++++++++++++++ 2 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 tests/integration/Core/Repository/ContentService/ContentUpdateAfterAddingFieldDefinitionTest.php diff --git a/src/lib/Persistence/Legacy/Content/FieldHandler.php b/src/lib/Persistence/Legacy/Content/FieldHandler.php index 892608c25c..6a5dbfafdc 100644 --- a/src/lib/Persistence/Legacy/Content/FieldHandler.php +++ b/src/lib/Persistence/Legacy/Content/FieldHandler.php @@ -334,10 +334,10 @@ public function updateFields(Content $content, UpdateStruct $updateStruct, Type $field->versionNo = $content->versionInfo->versionNo; if (isset($field->id) && array_key_exists($field->languageCode, $existingLanguageCodes)) { $this->updateField($field, $content); - $updatedFields[$fieldDefinition->id][$languageCode] = $field; } else { $this->createNewField($field, $content); } + $updatedFields[$fieldDefinition->id][$languageCode] = $field; } elseif (!isset($existingLanguageCodes[$languageCode])) { // If field is not set for new language if ($fieldDefinition->isTranslatable) { diff --git a/tests/integration/Core/Repository/ContentService/ContentUpdateAfterAddingFieldDefinitionTest.php b/tests/integration/Core/Repository/ContentService/ContentUpdateAfterAddingFieldDefinitionTest.php new file mode 100644 index 0000000000..10eca3062f --- /dev/null +++ b/tests/integration/Core/Repository/ContentService/ContentUpdateAfterAddingFieldDefinitionTest.php @@ -0,0 +1,149 @@ +createFieldDefinitionStruct('name', 'Name', true); + + $contentTypeCreateStruct = $this->createTypeCreateStruct(); + $contentTypeCreateStruct->addFieldDefinition($fieldDefCreateStruct); + + $contentType = $contentTypeService->createContentType($contentTypeCreateStruct, [ + $contentTypeService->loadContentTypeGroupByIdentifier('Content'), + ]); + + $contentTypeService->publishContentTypeDraft($contentType); + + // Create content, with two translations + $content = $this->createNewContent('Some Content', ['eng-US', 'ger-DE']); + + // Create draft in language with higher id ( later in the $contentLanguageService->loadLanguages() list than 'eng-US' ) + $content = $contentService->loadContent($content->getId(), ['eng-US']); + $engUpdateStruct = $this->createUpdateStruct($content, '', ['eng-US']); + $engDraft = $this->createContentDraft($content, 'eng-US'); + $engDraft = $this->updateContent($engDraft, $engUpdateStruct); + + // Create new non-translatable field + $contentType = $contentTypeService->loadContentTypeByIdentifier('multi_lang_drafts'); + $contentTypeDraft = $contentTypeService->createContentTypeDraft($contentType); + $fieldDefCreateStruct = $this->createFieldDefinitionStruct('non_trans_field', 'Non translatable field', false); + $contentTypeService->addFieldDefinition($contentTypeDraft, $fieldDefCreateStruct); + + $contentTypeService->publishContentTypeDraft($contentTypeDraft); + + // Update eng-US draft + $engUpdateStruct->setField('non_trans_field', '', 'eng-US'); + $this->updateContent($engDraft, $engUpdateStruct); + } + + private function createFieldDefinitionStruct(string $identifier, string $name, bool $isTranslatable): FieldDefinitionCreateStruct + { + $contentTypeService = self::getContentTypeService(); + + $fieldDefCreateStruct = $contentTypeService->newFieldDefinitionCreateStruct( + $identifier, + 'ezstring' + ); + + $fieldDefCreateStruct->names = ['eng-US' => $name]; + $fieldDefCreateStruct->descriptions = [ + 'eng-US' => '', + ]; + $fieldDefCreateStruct->isTranslatable = $isTranslatable; + + return $fieldDefCreateStruct; + } + + private function createTypeCreateStruct(): ContentTypeCreateStruct + { + $contentTypeService = self::getContentTypeService(); + $typeCreateStruct = $contentTypeService->newContentTypeCreateStruct('multi_lang_drafts'); + $typeCreateStruct->mainLanguageCode = 'eng-US'; + $typeCreateStruct->names = ['eng-US' => 'Multi lang drafts']; + + return $typeCreateStruct; + } + + /** + * @param string[] $languages + */ + protected function createNewContent(string $name, array $languages = ['eng-US'], int $parentLocationId = 2): Content + { + $contentTypeService = self::getContentTypeService(); + $contentService = self::getContentService(); + $locationService = self::getLocationService(); + + $contentType = $contentTypeService->loadContentTypeByIdentifier('multi_lang_drafts'); + $createStruct = $contentService->newContentCreateStruct($contentType, $languages[0]); + + foreach ($languages as $language) { + $createStruct->setField('name', "[$language]" . $name, $language); + } + $locationCreateStruct = $locationService->newLocationCreateStruct($parentLocationId); + + $draft = $contentService->createContent($createStruct, [$locationCreateStruct]); + + return $contentService->publishVersion($draft->versionInfo); + } + + /** + * @param string[] $languages + */ + protected function createUpdateStruct(Content $content, string $translatedName, array $languages): ContentUpdateStruct + { + $contentService = self::getContentService(); + + $updateStruct = $contentService->newContentUpdateStruct(); + $updateStruct->initialLanguageCode = $languages[0]; + + if ($translatedName === '') { + $translatedNameOrg = $content->getName(); + } else { + $translatedNameOrg = $translatedName; + } + + foreach ($languages as $language) { + $translatedName = "[$language]" . $translatedNameOrg; + + $updateStruct->setField('name', $translatedName, $language); + } + + return $updateStruct; + } + + protected function createContentDraft(Content $content, string $languageCode): Content + { + $contentLanguageService = self::getLanguageService(); + + $language = $contentLanguageService->loadLanguage($languageCode); + + return self::getContentService()->createContentDraft($content->contentInfo, null, null, $language); + } + + protected function updateContent(Content $draft, ContentUpdateStruct $updateStruct): Content + { + return self::getContentService()->updateContent($draft->versionInfo, $updateStruct); + } +}