diff --git a/composer.lock b/composer.lock
index c479d6171..6778ccbcc 100644
--- a/composer.lock
+++ b/composer.lock
@@ -2535,16 +2535,16 @@
},
{
"name": "drupal/core",
- "version": "11.3.5",
+ "version": "11.3.8",
"source": {
"type": "git",
"url": "https://github.com/drupal/core.git",
- "reference": "6de8a6ff360ad1c2719af077259c3ef77ba3d23f"
+ "reference": "d40f45fa436fb089cd54029d2dab387c3040fc2c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/drupal/core/zipball/6de8a6ff360ad1c2719af077259c3ef77ba3d23f",
- "reference": "6de8a6ff360ad1c2719af077259c3ef77ba3d23f",
+ "url": "https://api.github.com/repos/drupal/core/zipball/d40f45fa436fb089cd54029d2dab387c3040fc2c",
+ "reference": "d40f45fa436fb089cd54029d2dab387c3040fc2c",
"shasum": ""
},
"require": {
@@ -2702,13 +2702,13 @@
],
"description": "Drupal is an open source content management platform powering millions of websites and applications.",
"support": {
- "source": "https://github.com/drupal/core/tree/11.3.5"
+ "source": "https://github.com/drupal/core/tree/11.3.8"
},
- "time": "2026-03-06T09:54:42+00:00"
+ "time": "2026-04-20T07:33:20+00:00"
},
{
"name": "drupal/core-composer-scaffold",
- "version": "11.3.5",
+ "version": "11.3.8",
"source": {
"type": "git",
"url": "https://github.com/drupal/core-composer-scaffold.git",
@@ -2752,7 +2752,7 @@
"drupal"
],
"support": {
- "source": "https://github.com/drupal/core-composer-scaffold/tree/11.3.5"
+ "source": "https://github.com/drupal/core-composer-scaffold/tree/11.3.8"
},
"time": "2026-02-10T11:39:53+00:00"
},
@@ -2815,26 +2815,26 @@
},
{
"name": "drupal/csp",
- "version": "2.2.2",
+ "version": "2.2.3",
"source": {
"type": "git",
"url": "https://git.drupalcode.org/project/csp.git",
- "reference": "2.2.2"
+ "reference": "2.2.3"
},
"dist": {
"type": "zip",
- "url": "https://ftp.drupal.org/files/projects/csp-2.2.2.zip",
- "reference": "2.2.2",
- "shasum": "4ae305859e6997c62296ddbeee480ba619557fe8"
+ "url": "https://ftp.drupal.org/files/projects/csp-2.2.3.zip",
+ "reference": "2.2.3",
+ "shasum": "a02939b221ecb66273530d7be3b2a287f897fa3c"
},
"require": {
- "drupal/core": "^10.2 || ^11"
+ "drupal/core": "^11.2 || ^12"
},
"type": "drupal-module",
"extra": {
"drupal": {
- "version": "2.2.2",
- "datestamp": "1741822236",
+ "version": "2.2.3",
+ "datestamp": "1776729271",
"security-coverage": {
"status": "covered",
"message": "Covered by Drupal's security advisory policy"
@@ -3815,17 +3815,17 @@
},
{
"name": "drupal/external_entities",
- "version": "3.0.0-rc1",
+ "version": "3.0.0-rc2",
"source": {
"type": "git",
"url": "https://git.drupalcode.org/project/external_entities.git",
- "reference": "3.0.0-rc1"
+ "reference": "3.0.0-rc2"
},
"dist": {
"type": "zip",
- "url": "https://ftp.drupal.org/files/projects/external_entities-3.0.0-rc1.zip",
- "reference": "3.0.0-rc1",
- "shasum": "7319be341c37a0763a32815edba1a98081efc11e"
+ "url": "https://ftp.drupal.org/files/projects/external_entities-3.0.0-rc2.zip",
+ "reference": "3.0.0-rc2",
+ "shasum": "a6e1f6e0194bdad17b41f258772e829edeb3e220"
},
"require": {
"drupal/core": "^10 || ^11",
@@ -3838,8 +3838,8 @@
"type": "drupal-module",
"extra": {
"drupal": {
- "version": "3.0.0-rc1",
- "datestamp": "1769878913",
+ "version": "3.0.0-rc2",
+ "datestamp": "1776284356",
"security-coverage": {
"status": "not-covered",
"message": "RC releases are not covered by Drupal security advisories."
@@ -4357,16 +4357,16 @@
},
{
"name": "drupal/hdbt",
- "version": "6.16.60",
+ "version": "6.16.70",
"source": {
"type": "git",
"url": "https://github.com/City-of-Helsinki/drupal-hdbt.git",
- "reference": "65ed94c157f3e1c02a77a35aeed75110142008ac"
+ "reference": "b30aa236a9a992b9f53adfb0bd72e25fcb0c7d94"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/City-of-Helsinki/drupal-hdbt/zipball/65ed94c157f3e1c02a77a35aeed75110142008ac",
- "reference": "65ed94c157f3e1c02a77a35aeed75110142008ac",
+ "url": "https://api.github.com/repos/City-of-Helsinki/drupal-hdbt/zipball/b30aa236a9a992b9f53adfb0bd72e25fcb0c7d94",
+ "reference": "b30aa236a9a992b9f53adfb0bd72e25fcb0c7d94",
"shasum": ""
},
"require": {
@@ -4385,10 +4385,10 @@
"Drupal"
],
"support": {
- "source": "https://github.com/City-of-Helsinki/drupal-hdbt/tree/6.16.60",
+ "source": "https://github.com/City-of-Helsinki/drupal-hdbt/tree/6.16.70",
"issues": "https://github.com/City-of-Helsinki/drupal-hdbt/issues"
},
- "time": "2026-04-02T13:27:44+00:00"
+ "time": "2026-04-21T07:27:59+00:00"
},
{
"name": "drupal/hdbt_admin",
@@ -4479,16 +4479,16 @@
},
{
"name": "drupal/helfi_api_base",
- "version": "2.8.15",
+ "version": "2.8.19",
"source": {
"type": "git",
"url": "https://github.com/City-of-Helsinki/drupal-module-helfi-api-base.git",
- "reference": "1b0a72acbc78b4c95c0f760eb806ef2908156d64"
+ "reference": "989784a16b9f4336a67e8d2c33e71f44813bd45d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/City-of-Helsinki/drupal-module-helfi-api-base/zipball/1b0a72acbc78b4c95c0f760eb806ef2908156d64",
- "reference": "1b0a72acbc78b4c95c0f760eb806ef2908156d64",
+ "url": "https://api.github.com/repos/City-of-Helsinki/drupal-module-helfi-api-base/zipball/989784a16b9f4336a67e8d2c33e71f44813bd45d",
+ "reference": "989784a16b9f4336a67e8d2c33e71f44813bd45d",
"shasum": ""
},
"require": {
@@ -4497,7 +4497,8 @@
"drupal/entity": "^1.0",
"drupal/health_check": "^3.0",
"drupal/monolog": "^3.0",
- "drupal/raven": "^5.0 || ^6.0",
+ "drupal/raven": "^6.0 || ^7.0",
+ "drupal/redis": "^1.0",
"ext-curl": "*",
"firebase/php-jwt": "^7.0",
"php": "^8.1",
@@ -4530,10 +4531,10 @@
],
"description": "Helfi - API Base",
"support": {
- "source": "https://github.com/City-of-Helsinki/drupal-module-helfi-api-base/tree/2.8.15",
+ "source": "https://github.com/City-of-Helsinki/drupal-module-helfi-api-base/tree/2.8.19",
"issues": "https://github.com/City-of-Helsinki/drupal-module-helfi-api-base/issues"
},
- "time": "2026-04-07T06:25:24+00:00"
+ "time": "2026-04-21T08:39:47+00:00"
},
{
"name": "drupal/helfi_azure_fs",
@@ -4661,16 +4662,16 @@
},
{
"name": "drupal/helfi_hakuvahti",
- "version": "1.2.3",
+ "version": "1.2.4",
"source": {
"type": "git",
"url": "https://github.com/City-of-Helsinki/drupal-module-helfi-hakuvahti.git",
- "reference": "fc44c07faf61c24f8f6238fa2a9d7380e90f80b4"
+ "reference": "f6e86aa805455f2a736a9f9bb7bb23f0647bda1b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/City-of-Helsinki/drupal-module-helfi-hakuvahti/zipball/fc44c07faf61c24f8f6238fa2a9d7380e90f80b4",
- "reference": "fc44c07faf61c24f8f6238fa2a9d7380e90f80b4",
+ "url": "https://api.github.com/repos/City-of-Helsinki/drupal-module-helfi-hakuvahti/zipball/f6e86aa805455f2a736a9f9bb7bb23f0647bda1b",
+ "reference": "f6e86aa805455f2a736a9f9bb7bb23f0647bda1b",
"shasum": ""
},
"require": {
@@ -4686,10 +4687,10 @@
],
"description": "Helfi - Hakuvahti",
"support": {
- "source": "https://github.com/City-of-Helsinki/drupal-module-helfi-hakuvahti/tree/1.2.3",
+ "source": "https://github.com/City-of-Helsinki/drupal-module-helfi-hakuvahti/tree/1.2.4",
"issues": "https://github.com/City-of-Helsinki/drupal-module-helfi-hakuvahti/issues"
},
- "time": "2026-03-23T09:43:42+00:00"
+ "time": "2026-04-13T12:35:08+00:00"
},
{
"name": "drupal/helfi_navigation",
@@ -4727,16 +4728,16 @@
},
{
"name": "drupal/helfi_platform_config",
- "version": "5.1.35",
+ "version": "5.1.42",
"source": {
"type": "git",
"url": "https://github.com/City-of-Helsinki/drupal-helfi-platform-config.git",
- "reference": "ce367bb2c3fd801c0ffa421e6f17328932bda0b1"
+ "reference": "90ea1221ee2bb76d7bf4966d0888ed876809cce4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/City-of-Helsinki/drupal-helfi-platform-config/zipball/ce367bb2c3fd801c0ffa421e6f17328932bda0b1",
- "reference": "ce367bb2c3fd801c0ffa421e6f17328932bda0b1",
+ "url": "https://api.github.com/repos/City-of-Helsinki/drupal-helfi-platform-config/zipball/90ea1221ee2bb76d7bf4966d0888ed876809cce4",
+ "reference": "90ea1221ee2bb76d7bf4966d0888ed876809cce4",
"shasum": ""
},
"require": {
@@ -4806,6 +4807,7 @@
"symfony/property-access": "^7.3"
},
"conflict": {
+ "drupal/core": "<11.3.8",
"drupal/external_entities": "<3.0.0-beta7",
"drush/drush": "<12"
},
@@ -4815,11 +4817,11 @@
"drupal/core": {
"[#UHF-12709] Patch 'Deleted and replaced ...' error messages": "./public/modules/contrib/helfi_platform_config/patches/UHF-12709-skip_deleted_and_replaced_log.patch",
"[#UHF-181] Hide untranslated menu links (https://www.drupal.org/project/drupal/issues/3091246)": "./public/modules/contrib/helfi_platform_config/patches/3091246.patch",
- "[#UHF-3812] Ajax exposed filters not working for multiple instances of the same Views block placed on one page (https://www.drupal.org/project/drupal/issues/3163299)": "https://www.drupal.org/files/issues/2023-05-07/3163299-104-D10.patch",
+ "[#UHF-3812] Ajax exposed filters not working for multiple instances of the same Views block placed on one page (https://www.drupal.org/project/drupal/issues/3163299)": "./public/modules/contrib/helfi_platform_config/patches/3163299-104-D10.patch",
"[#UHF-4325] Strip whitespaces from twig debug comments": "./public/modules/contrib/helfi_platform_config/patches/drupal_core_strip_debug_mode_whitespaces_11.3.x.patch",
"[#UHF-7008] Add multilingual support for caching basefield definitions (https://www.drupal.org/project/drupal/issues/3114824)": "./public/modules/contrib/helfi_platform_config/patches/3114824.patch",
"[#UHF-7008] Admin toolbar and contextual links should always be rendered in the admin language (https://www.drupal.org/project/drupal/issues/2313309)": "./public/modules/contrib/helfi_platform_config/patches/2313309.patch",
- "[#UHF-9690] Allow updating lists when switching from allowed values to allowed values function (https://www.drupal.org/i/2873353)": "https://www.drupal.org/files/issues/2025-06-27/allow-allowed-values-function-update-2873353-20.patch",
+ "[#UHF-9690] Allow updating lists when switching from allowed values to allowed values function (https://www.drupal.org/i/2873353)": "./public/modules/contrib/helfi_platform_config/patches/2873353-20.patch",
"[#UHF-9952, #UHF-9980] Duplicate
tags (https://www.drupal.org/i/3083786)": "./public/modules/contrib/helfi_platform_config/patches/3083786.patch",
"[#UHF-11025] Status message templates missing theme when bigpipe is enabled (https://www.drupal.org/i/3396318)": "./public/modules/contrib/helfi_platform_config/patches/3396318.patch",
"[#UHF-11784] Sort the source and target arrays in the configuration storage comparer to avoid false positives": "./public/modules/contrib/helfi_platform_config/patches/drupal-core-sort-storage-comparer-source-and-target-arrays.patch"
@@ -4837,7 +4839,7 @@
"https://www.drupal.org/project/default_content/issues/2640734#comment-14638943": "./public/modules/contrib/helfi_platform_config/patches/default_content_2.0.0-alpha3-2640734_manual_imports.patch"
},
"drupal/paragraphs": {
- "https://www.drupal.org/project/paragraphs/issues/2904705#comment-13836790": "https://www.drupal.org/files/issues/2020-09-25/2904705-115.patch",
+ "https://www.drupal.org/project/paragraphs/issues/2904705#comment-13836790": "./public/modules/contrib/helfi_platform_config/patches/2904705-115.patch",
"[#UHF-2059] Enhancements for the Admin UI": "./public/modules/contrib/helfi_platform_config/patches/helfi_customizations_for_paragraphs_widget_8.x-1.12.patch",
"[#UHF-10840] https://www.drupal.org/i/3510842: Duplicating nested paragraph overwriting paragraph references": "./public/modules/contrib/helfi_platform_config/patches/paragraphs-3510842-duplicate_paragraph_overwrite.patch"
},
@@ -4851,23 +4853,23 @@
],
"description": "HELfi platform config",
"support": {
- "source": "https://github.com/City-of-Helsinki/drupal-helfi-platform-config/tree/5.1.35",
+ "source": "https://github.com/City-of-Helsinki/drupal-helfi-platform-config/tree/5.1.42",
"issues": "https://github.com/City-of-Helsinki/drupal-helfi-platform-config/issues"
},
- "time": "2026-04-08T06:21:41+00:00"
+ "time": "2026-04-21T10:23:14+00:00"
},
{
"name": "drupal/helfi_proxy",
- "version": "3.4.0",
+ "version": "3.4.1",
"source": {
"type": "git",
"url": "https://github.com/City-of-Helsinki/drupal-module-helfi-proxy.git",
- "reference": "f3f460548b0848d22bd889f4826b825e4aa103f6"
+ "reference": "7cfd008ab8668254f2522ee9bef8e9008c90425a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/City-of-Helsinki/drupal-module-helfi-proxy/zipball/f3f460548b0848d22bd889f4826b825e4aa103f6",
- "reference": "f3f460548b0848d22bd889f4826b825e4aa103f6",
+ "url": "https://api.github.com/repos/City-of-Helsinki/drupal-module-helfi-proxy/zipball/7cfd008ab8668254f2522ee9bef8e9008c90425a",
+ "reference": "7cfd008ab8668254f2522ee9bef8e9008c90425a",
"shasum": ""
},
"require": {
@@ -4897,10 +4899,10 @@
],
"description": "Provides various fixes so we can serve multiple Drupal instances in one domain.",
"support": {
- "source": "https://github.com/City-of-Helsinki/drupal-module-helfi-proxy/tree/3.4.0",
+ "source": "https://github.com/City-of-Helsinki/drupal-module-helfi-proxy/tree/3.4.1",
"issues": "https://github.com/City-of-Helsinki/drupal-module-helfi-proxy/issues"
},
- "time": "2025-11-21T14:03:03+00:00"
+ "time": "2026-04-21T07:08:58+00:00"
},
{
"name": "drupal/helfi_tpr",
@@ -6317,33 +6319,33 @@
},
{
"name": "drupal/raven",
- "version": "6.0.16",
+ "version": "7.3.8",
"source": {
"type": "git",
"url": "https://git.drupalcode.org/project/raven.git",
- "reference": "6.0.16"
+ "reference": "7.3.8"
},
"dist": {
"type": "zip",
- "url": "https://ftp.drupal.org/files/projects/raven-6.0.16.zip",
- "reference": "6.0.16",
- "shasum": "7859678b6c935afbdacf72f5ca3508784d9b0948"
+ "url": "https://ftp.drupal.org/files/projects/raven-7.3.8.zip",
+ "reference": "7.3.8",
+ "shasum": "78e4219650a9b49a7f35ae165cb8d6077ceb46bc"
},
"require": {
- "drupal/core": "^10.2 || ^11",
- "sentry/sentry": "^4.9"
+ "drupal/core": "^11.1",
+ "sentry/sentry": "^4.20"
},
"require-dev": {
"drupal/csp": "^1.17 || ^2.0",
"drupal/monitoring": "^1.13",
"drupal/seckit": "^2.0",
- "drush/drush": "^11.0 || ^12.0 || ^13.0"
+ "drush/drush": "^13.0"
},
"type": "drupal-module",
"extra": {
"drupal": {
- "version": "6.0.16",
- "datestamp": "1755300523",
+ "version": "7.3.8",
+ "datestamp": "1775584686",
"security-coverage": {
"status": "covered",
"message": "Covered by Drupal's security advisory policy"
@@ -6372,6 +6374,10 @@
"type": "github",
"url": "https://github.com/sponsors/mfb"
},
+ {
+ "type": "ko-fi",
+ "url": "https://ko-fi.com/mfb"
+ },
{
"type": "patreon",
"url": "https://www.patreon.com/mfb"
@@ -8373,12 +8379,12 @@
"version": "v7.0.5",
"source": {
"type": "git",
- "url": "https://github.com/firebase/php-jwt.git",
+ "url": "https://github.com/googleapis/php-jwt.git",
"reference": "47ad26bab5e7c70ae8a6f08ed25ff83631121380"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/firebase/php-jwt/zipball/47ad26bab5e7c70ae8a6f08ed25ff83631121380",
+ "url": "https://api.github.com/repos/googleapis/php-jwt/zipball/47ad26bab5e7c70ae8a6f08ed25ff83631121380",
"reference": "47ad26bab5e7c70ae8a6f08ed25ff83631121380",
"shasum": ""
},
@@ -8427,8 +8433,8 @@
"php"
],
"support": {
- "issues": "https://github.com/firebase/php-jwt/issues",
- "source": "https://github.com/firebase/php-jwt/tree/v7.0.5"
+ "issues": "https://github.com/googleapis/php-jwt/issues",
+ "source": "https://github.com/googleapis/php-jwt/tree/v7.0.5"
},
"time": "2026-04-01T20:38:03+00:00"
},
@@ -8979,16 +8985,16 @@
},
{
"name": "laravel/prompts",
- "version": "v0.3.16",
+ "version": "v0.3.17",
"source": {
"type": "git",
"url": "https://github.com/laravel/prompts.git",
- "reference": "11e7d5f93803a2190b00e145142cb00a33d17ad2"
+ "reference": "6a82ac19a28b916ae0885828795dbd4c59d9a818"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/prompts/zipball/11e7d5f93803a2190b00e145142cb00a33d17ad2",
- "reference": "11e7d5f93803a2190b00e145142cb00a33d17ad2",
+ "url": "https://api.github.com/repos/laravel/prompts/zipball/6a82ac19a28b916ae0885828795dbd4c59d9a818",
+ "reference": "6a82ac19a28b916ae0885828795dbd4c59d9a818",
"shasum": ""
},
"require": {
@@ -9032,9 +9038,9 @@
"description": "Add beautiful and user-friendly forms to your command-line applications.",
"support": {
"issues": "https://github.com/laravel/prompts/issues",
- "source": "https://github.com/laravel/prompts/tree/v0.3.16"
+ "source": "https://github.com/laravel/prompts/tree/v0.3.17"
},
- "time": "2026-03-23T14:35:33+00:00"
+ "time": "2026-04-20T16:07:33+00:00"
},
{
"name": "league/container",
@@ -10011,6 +10017,84 @@
},
"time": "2025-12-06T11:56:16+00:00"
},
+ {
+ "name": "nyholm/psr7",
+ "version": "1.8.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Nyholm/psr7.git",
+ "reference": "a71f2b11690f4b24d099d6b16690a90ae14fc6f3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Nyholm/psr7/zipball/a71f2b11690f4b24d099d6b16690a90ae14fc6f3",
+ "reference": "a71f2b11690f4b24d099d6b16690a90ae14fc6f3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2",
+ "psr/http-factory": "^1.0",
+ "psr/http-message": "^1.1 || ^2.0"
+ },
+ "provide": {
+ "php-http/message-factory-implementation": "1.0",
+ "psr/http-factory-implementation": "1.0",
+ "psr/http-message-implementation": "1.0"
+ },
+ "require-dev": {
+ "http-interop/http-factory-tests": "^0.9",
+ "php-http/message-factory": "^1.0",
+ "php-http/psr7-integration-tests": "^1.0",
+ "phpunit/phpunit": "^7.5 || ^8.5 || ^9.4",
+ "symfony/error-handler": "^4.4"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.8-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Nyholm\\Psr7\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Tobias Nyholm",
+ "email": "tobias.nyholm@gmail.com"
+ },
+ {
+ "name": "Martijn van der Ven",
+ "email": "martijn@vanderven.se"
+ }
+ ],
+ "description": "A fast PHP7 implementation of PSR-7",
+ "homepage": "https://tnyholm.se",
+ "keywords": [
+ "psr-17",
+ "psr-7"
+ ],
+ "support": {
+ "issues": "https://github.com/Nyholm/psr7/issues",
+ "source": "https://github.com/Nyholm/psr7/tree/1.8.2"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/Zegnat",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nyholm",
+ "type": "github"
+ }
+ ],
+ "time": "2024-09-09T07:06:30+00:00"
+ },
{
"name": "open-telemetry/api",
"version": "1.9.0",
@@ -11359,35 +11443,36 @@
},
{
"name": "phrity/websocket",
- "version": "3.6.2",
+ "version": "3.7.0",
"source": {
"type": "git",
"url": "https://github.com/sirn-se/websocket-php.git",
- "reference": "b9816ed2b4a10c8c42bd0b6398044ab506869756"
+ "reference": "01f15374987d8281dba0ca511f322a0e18229330"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sirn-se/websocket-php/zipball/b9816ed2b4a10c8c42bd0b6398044ab506869756",
- "reference": "b9816ed2b4a10c8c42bd0b6398044ab506869756",
+ "url": "https://api.github.com/repos/sirn-se/websocket-php/zipball/01f15374987d8281dba0ca511f322a0e18229330",
+ "reference": "01f15374987d8281dba0ca511f322a0e18229330",
"shasum": ""
},
"require": {
+ "nyholm/psr7": "^1.4",
"php": "^8.1",
- "phrity/http": "^1.0",
- "phrity/net-stream": "^2.3",
+ "phrity/http": "^1.1",
+ "phrity/net-stream": "^2.4",
"phrity/net-uri": "^2.1",
- "psr/http-message": "^1.1 | ^2.0",
+ "psr/http-factory": "^1.0",
+ "psr/http-message": "^1.1 || ^2.0",
"psr/log": "^1.0 || ^2.0 || ^3.0"
},
"require-dev": {
- "guzzlehttp/psr7": "^2.0",
"phpstan/phpstan": "^2.0",
- "phpunit/phpunit": "^10.0 || ^11.0 || ^12.0",
+ "phpunit/phpunit": "^10.0 || ^11.0 || ^12.0 || ^13.0",
"phrity/logger-console": "^1.0",
- "phrity/net-mock": "^2.3",
+ "phrity/net-mock": "^2.4",
"phrity/util-errorhandler": "^1.1",
"robiningelbrecht/phpunit-coverage-tools": "^1.9",
- "squizlabs/php_codesniffer": "^3.5 || ^4.0"
+ "squizlabs/php_codesniffer": "^4.0"
},
"type": "library",
"autoload": {
@@ -11418,9 +11503,9 @@
],
"support": {
"issues": "https://github.com/sirn-se/websocket-php/issues",
- "source": "https://github.com/sirn-se/websocket-php/tree/3.6.2"
+ "source": "https://github.com/sirn-se/websocket-php/tree/3.7.0"
},
- "time": "2025-12-21T09:58:16+00:00"
+ "time": "2026-04-06T18:18:14+00:00"
},
{
"name": "proj4php/proj4php",
@@ -13367,16 +13452,16 @@
},
{
"name": "symfony/polyfill-ctype",
- "version": "v1.33.0",
+ "version": "v1.36.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
- "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
+ "reference": "141046a8f9477948ff284fa65be2095baafb94f2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
- "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/141046a8f9477948ff284fa65be2095baafb94f2",
+ "reference": "141046a8f9477948ff284fa65be2095baafb94f2",
"shasum": ""
},
"require": {
@@ -13426,7 +13511,7 @@
"portable"
],
"support": {
- "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0"
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.36.0"
},
"funding": [
{
@@ -13446,20 +13531,20 @@
"type": "tidelift"
}
],
- "time": "2024-09-09T11:45:10+00:00"
+ "time": "2026-04-10T16:19:22+00:00"
},
{
"name": "symfony/polyfill-iconv",
- "version": "v1.33.0",
+ "version": "v1.36.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-iconv.git",
- "reference": "5f3b930437ae03ae5dff61269024d8ea1b3774aa"
+ "reference": "2c5729fd241b4b22f6e4b436bc3354a4f262df57"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/5f3b930437ae03ae5dff61269024d8ea1b3774aa",
- "reference": "5f3b930437ae03ae5dff61269024d8ea1b3774aa",
+ "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/2c5729fd241b4b22f6e4b436bc3354a4f262df57",
+ "reference": "2c5729fd241b4b22f6e4b436bc3354a4f262df57",
"shasum": ""
},
"require": {
@@ -13510,7 +13595,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-iconv/tree/v1.33.0"
+ "source": "https://github.com/symfony/polyfill-iconv/tree/v1.36.0"
},
"funding": [
{
@@ -13530,20 +13615,20 @@
"type": "tidelift"
}
],
- "time": "2024-09-17T14:58:18+00:00"
+ "time": "2026-04-10T16:19:22+00:00"
},
{
"name": "symfony/polyfill-intl-grapheme",
- "version": "v1.33.0",
+ "version": "v1.36.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
- "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70"
+ "reference": "ad1b7b9092976d6c948b8a187cec9faaea9ec1df"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70",
- "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/ad1b7b9092976d6c948b8a187cec9faaea9ec1df",
+ "reference": "ad1b7b9092976d6c948b8a187cec9faaea9ec1df",
"shasum": ""
},
"require": {
@@ -13592,7 +13677,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0"
+ "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.36.0"
},
"funding": [
{
@@ -13612,11 +13697,11 @@
"type": "tidelift"
}
],
- "time": "2025-06-27T09:58:17+00:00"
+ "time": "2026-04-10T16:19:22+00:00"
},
{
"name": "symfony/polyfill-intl-idn",
- "version": "v1.33.0",
+ "version": "v1.36.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-idn.git",
@@ -13679,7 +13764,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.33.0"
+ "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.36.0"
},
"funding": [
{
@@ -13703,7 +13788,7 @@
},
{
"name": "symfony/polyfill-intl-normalizer",
- "version": "v1.33.0",
+ "version": "v1.36.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
@@ -13764,7 +13849,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0"
+ "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.36.0"
},
"funding": [
{
@@ -13788,16 +13873,16 @@
},
{
"name": "symfony/polyfill-mbstring",
- "version": "v1.33.0",
+ "version": "v1.36.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
+ "reference": "6a21eb99c6973357967f6ce3708cd55a6bec6315"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
- "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6a21eb99c6973357967f6ce3708cd55a6bec6315",
+ "reference": "6a21eb99c6973357967f6ce3708cd55a6bec6315",
"shasum": ""
},
"require": {
@@ -13849,7 +13934,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0"
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.36.0"
},
"funding": [
{
@@ -13869,7 +13954,7 @@
"type": "tidelift"
}
],
- "time": "2024-12-23T08:48:59+00:00"
+ "time": "2026-04-10T17:25:58+00:00"
},
{
"name": "symfony/polyfill-php56",
@@ -13941,7 +14026,7 @@
},
{
"name": "symfony/polyfill-php81",
- "version": "v1.33.0",
+ "version": "v1.36.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php81.git",
@@ -13997,7 +14082,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php81/tree/v1.33.0"
+ "source": "https://github.com/symfony/polyfill-php81/tree/v1.36.0"
},
"funding": [
{
@@ -14021,16 +14106,16 @@
},
{
"name": "symfony/polyfill-php82",
- "version": "v1.33.0",
+ "version": "v1.36.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php82.git",
- "reference": "5d2ed36f7734637dacc025f179698031951b1692"
+ "reference": "34808efe3e68f69685796f7c253a2f1d8ea9df59"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php82/zipball/5d2ed36f7734637dacc025f179698031951b1692",
- "reference": "5d2ed36f7734637dacc025f179698031951b1692",
+ "url": "https://api.github.com/repos/symfony/polyfill-php82/zipball/34808efe3e68f69685796f7c253a2f1d8ea9df59",
+ "reference": "34808efe3e68f69685796f7c253a2f1d8ea9df59",
"shasum": ""
},
"require": {
@@ -14077,7 +14162,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php82/tree/v1.33.0"
+ "source": "https://github.com/symfony/polyfill-php82/tree/v1.36.0"
},
"funding": [
{
@@ -14097,20 +14182,20 @@
"type": "tidelift"
}
],
- "time": "2024-09-09T11:45:10+00:00"
+ "time": "2026-04-10T16:19:22+00:00"
},
{
"name": "symfony/polyfill-php83",
- "version": "v1.33.0",
+ "version": "v1.36.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php83.git",
- "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5"
+ "reference": "3600c2cb22399e25bb226e4a135ce91eeb2a6149"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5",
- "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5",
+ "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/3600c2cb22399e25bb226e4a135ce91eeb2a6149",
+ "reference": "3600c2cb22399e25bb226e4a135ce91eeb2a6149",
"shasum": ""
},
"require": {
@@ -14157,7 +14242,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0"
+ "source": "https://github.com/symfony/polyfill-php83/tree/v1.36.0"
},
"funding": [
{
@@ -14177,20 +14262,20 @@
"type": "tidelift"
}
],
- "time": "2025-07-08T02:45:35+00:00"
+ "time": "2026-04-10T17:25:58+00:00"
},
{
"name": "symfony/polyfill-php84",
- "version": "v1.33.0",
+ "version": "v1.36.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php84.git",
- "reference": "d8ced4d875142b6a7426000426b8abc631d6b191"
+ "reference": "88486db2c389b290bf87ff1de7ebc1e13e42bb06"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191",
- "reference": "d8ced4d875142b6a7426000426b8abc631d6b191",
+ "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/88486db2c389b290bf87ff1de7ebc1e13e42bb06",
+ "reference": "88486db2c389b290bf87ff1de7ebc1e13e42bb06",
"shasum": ""
},
"require": {
@@ -14237,7 +14322,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php84/tree/v1.33.0"
+ "source": "https://github.com/symfony/polyfill-php84/tree/v1.36.0"
},
"funding": [
{
@@ -14257,20 +14342,20 @@
"type": "tidelift"
}
],
- "time": "2025-06-24T13:30:11+00:00"
+ "time": "2026-04-10T18:47:49+00:00"
},
{
"name": "symfony/polyfill-php85",
- "version": "v1.33.0",
+ "version": "v1.36.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php85.git",
- "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91"
+ "reference": "2c408a6bb0313e6001a83628dc5506100474254e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91",
- "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91",
+ "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/2c408a6bb0313e6001a83628dc5506100474254e",
+ "reference": "2c408a6bb0313e6001a83628dc5506100474254e",
"shasum": ""
},
"require": {
@@ -14317,7 +14402,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php85/tree/v1.33.0"
+ "source": "https://github.com/symfony/polyfill-php85/tree/v1.36.0"
},
"funding": [
{
@@ -14337,7 +14422,7 @@
"type": "tidelift"
}
],
- "time": "2025-06-23T16:12:55+00:00"
+ "time": "2026-04-10T16:50:15+00:00"
},
{
"name": "symfony/process",
@@ -16141,16 +16226,16 @@
},
{
"name": "composer/composer",
- "version": "2.9.5",
+ "version": "2.9.7",
"source": {
"type": "git",
"url": "https://github.com/composer/composer.git",
- "reference": "72a8f8e653710e18d83e5dd531eb5a71fc3223e6"
+ "reference": "82a2fbd1372a98d7915cfb092acf05207d9b4113"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/composer/zipball/72a8f8e653710e18d83e5dd531eb5a71fc3223e6",
- "reference": "72a8f8e653710e18d83e5dd531eb5a71fc3223e6",
+ "url": "https://api.github.com/repos/composer/composer/zipball/82a2fbd1372a98d7915cfb092acf05207d9b4113",
+ "reference": "82a2fbd1372a98d7915cfb092acf05207d9b4113",
"shasum": ""
},
"require": {
@@ -16238,7 +16323,7 @@
"irc": "ircs://irc.libera.chat:6697/composer",
"issues": "https://github.com/composer/composer/issues",
"security": "https://github.com/composer/composer/security/policy",
- "source": "https://github.com/composer/composer/tree/2.9.5"
+ "source": "https://github.com/composer/composer/tree/2.9.7"
},
"funding": [
{
@@ -16250,7 +16335,7 @@
"type": "github"
}
],
- "time": "2026-01-29T10:40:53+00:00"
+ "time": "2026-04-14T11:31:52+00:00"
},
{
"name": "composer/metadata-minifier",
@@ -16402,24 +16487,24 @@
},
{
"name": "composer/spdx-licenses",
- "version": "1.5.9",
+ "version": "1.6.0",
"source": {
"type": "git",
"url": "https://github.com/composer/spdx-licenses.git",
- "reference": "edf364cefe8c43501e21e88110aac10b284c3c9f"
+ "reference": "5ecd0cb4177696f9fd48f1605dda81db3dee7889"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/edf364cefe8c43501e21e88110aac10b284c3c9f",
- "reference": "edf364cefe8c43501e21e88110aac10b284c3c9f",
+ "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/5ecd0cb4177696f9fd48f1605dda81db3dee7889",
+ "reference": "5ecd0cb4177696f9fd48f1605dda81db3dee7889",
"shasum": ""
},
"require": {
- "php": "^5.3.2 || ^7.0 || ^8.0"
+ "php": "^7.2 || ^8.0"
},
"require-dev": {
"phpstan/phpstan": "^1.11",
- "symfony/phpunit-bridge": "^3 || ^7"
+ "symfony/phpunit-bridge": "^6.4.25 || ^7.3.3 || ^8.0"
},
"type": "library",
"extra": {
@@ -16462,7 +16547,7 @@
"support": {
"irc": "ircs://irc.libera.chat:6697/composer",
"issues": "https://github.com/composer/spdx-licenses/issues",
- "source": "https://github.com/composer/spdx-licenses/tree/1.5.9"
+ "source": "https://github.com/composer/spdx-licenses/tree/1.6.0"
},
"funding": [
{
@@ -16472,13 +16557,9 @@
{
"url": "https://github.com/composer",
"type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/composer/composer",
- "type": "tidelift"
}
],
- "time": "2025-05-12T21:07:07+00:00"
+ "time": "2026-04-08T20:18:39+00:00"
},
{
"name": "composer/xdebug-handler",
@@ -16796,7 +16877,7 @@
},
{
"name": "drupal/core-dev",
- "version": "11.3.5",
+ "version": "11.3.8",
"source": {
"type": "git",
"url": "https://github.com/drupal/core-dev.git",
@@ -16846,7 +16927,7 @@
],
"description": "require-dev dependencies from drupal/drupal; use in addition to drupal/core-recommended to run tests from drupal/core.",
"support": {
- "source": "https://github.com/drupal/core-dev/tree/11.3.5"
+ "source": "https://github.com/drupal/core-dev/tree/11.3.8"
},
"time": "2026-02-04T09:01:40+00:00"
},
@@ -18192,16 +18273,16 @@
},
{
"name": "phpspec/prophecy",
- "version": "v1.26.0",
+ "version": "v1.26.1",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
- "reference": "0da07c10d5fe64cd0c748f0523b47599400f2ed1"
+ "reference": "09c2e5949d676286358a62af818f8407167a9dd6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpspec/prophecy/zipball/0da07c10d5fe64cd0c748f0523b47599400f2ed1",
- "reference": "0da07c10d5fe64cd0c748f0523b47599400f2ed1",
+ "url": "https://api.github.com/repos/phpspec/prophecy/zipball/09c2e5949d676286358a62af818f8407167a9dd6",
+ "reference": "09c2e5949d676286358a62af818f8407167a9dd6",
"shasum": ""
},
"require": {
@@ -18257,9 +18338,9 @@
],
"support": {
"issues": "https://github.com/phpspec/prophecy/issues",
- "source": "https://github.com/phpspec/prophecy/tree/v1.26.0"
+ "source": "https://github.com/phpspec/prophecy/tree/v1.26.1"
},
- "time": "2026-02-24T15:40:48+00:00"
+ "time": "2026-04-13T14:35:16+00:00"
},
{
"name": "phpspec/prophecy-phpunit",
@@ -20890,7 +20971,7 @@
},
{
"name": "symfony/polyfill-php73",
- "version": "v1.33.0",
+ "version": "v1.36.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php73.git",
@@ -20946,7 +21027,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php73/tree/v1.33.0"
+ "source": "https://github.com/symfony/polyfill-php73/tree/v1.36.0"
},
"funding": [
{
@@ -20970,16 +21051,16 @@
},
{
"name": "symfony/polyfill-php80",
- "version": "v1.33.0",
+ "version": "v1.36.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
- "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608"
+ "reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
- "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
+ "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dfb55726c3a76ea3b6459fcfda1ec2d80a682411",
+ "reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411",
"shasum": ""
},
"require": {
@@ -21030,7 +21111,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0"
+ "source": "https://github.com/symfony/polyfill-php80/tree/v1.36.0"
},
"funding": [
{
@@ -21050,7 +21131,7 @@
"type": "tidelift"
}
],
- "time": "2025-01-02T08:10:11+00:00"
+ "time": "2026-04-10T16:19:22+00:00"
},
{
"name": "tbachert/spi",
diff --git a/conf/cmi/core.entity_form_display.media.file.media_library.yml b/conf/cmi/core.entity_form_display.media.file.media_library.yml
index 6d659d4e5..9fc58014b 100644
--- a/conf/cmi/core.entity_form_display.media.file.media_library.yml
+++ b/conf/cmi/core.entity_form_display.media.file.media_library.yml
@@ -7,7 +7,7 @@ dependencies:
- field.field.media.file.field_media_file
- media.type.file
_core:
- default_config_hash: PnLUWOfSDV2wuJomGo-wDi3ndC1-Rp_qhZ6roAFuz0M
+ default_config_hash: 1DAJx9kbI8ZYNr04x4oOKphGJpxCk-VvNy15kZ5-I6w
id: media.file.media_library
targetEntityType: media
bundle: file
diff --git a/conf/cmi/core.entity_form_display.media.hel_map.media_library.yml b/conf/cmi/core.entity_form_display.media.hel_map.media_library.yml
index 89787e1ee..8a55f9deb 100644
--- a/conf/cmi/core.entity_form_display.media.hel_map.media_library.yml
+++ b/conf/cmi/core.entity_form_display.media.hel_map.media_library.yml
@@ -9,7 +9,7 @@ dependencies:
module:
- link
_core:
- default_config_hash: mB1qn09Anlv4NN5drGy-3Yp6eCU79CFve-VfKP_f7ag
+ default_config_hash: aRir_YGDHSxIqElevsVN6oe9_5_PkrcyWlJV5OoKKXQ
id: media.hel_map.media_library
targetEntityType: media
bundle: hel_map
diff --git a/conf/cmi/core.entity_form_display.media.helfi_chart.media_library.yml b/conf/cmi/core.entity_form_display.media.helfi_chart.media_library.yml
index 33b0e5d50..0232c7521 100644
--- a/conf/cmi/core.entity_form_display.media.helfi_chart.media_library.yml
+++ b/conf/cmi/core.entity_form_display.media.helfi_chart.media_library.yml
@@ -11,7 +11,7 @@ dependencies:
module:
- text
_core:
- default_config_hash: 7I7JgqwSLHKPVnnYpmVSQ0-RS8tUb0ayNGVynJiS_Jg
+ default_config_hash: aW9n1OCAr-p3GfXOj_Hv9qDgEvMKCb1FUzLVQY4-xSc
id: media.helfi_chart.media_library
targetEntityType: media
bundle: helfi_chart
diff --git a/conf/cmi/core.entity_form_display.media.image.media_library.yml b/conf/cmi/core.entity_form_display.media.image.media_library.yml
index 89b27e309..5590281cf 100644
--- a/conf/cmi/core.entity_form_display.media.image.media_library.yml
+++ b/conf/cmi/core.entity_form_display.media.image.media_library.yml
@@ -11,7 +11,7 @@ dependencies:
module:
- focal_point
_core:
- default_config_hash: sBZSklr6VL62q9muMdA81sfI53ReprPQkcd9IGCGEtI
+ default_config_hash: TJWhq-XZhpnNdLiW6qa38fYy05myTPDoAgni2M5RItg
id: media.image.media_library
targetEntityType: media
bundle: image
diff --git a/conf/cmi/core.entity_form_display.media.remote_video.media_library.yml b/conf/cmi/core.entity_form_display.media.remote_video.media_library.yml
index d9379d3ae..9bdfc2093 100644
--- a/conf/cmi/core.entity_form_display.media.remote_video.media_library.yml
+++ b/conf/cmi/core.entity_form_display.media.remote_video.media_library.yml
@@ -8,7 +8,7 @@ dependencies:
- field.field.media.remote_video.field_remote_video_videographer
- media.type.remote_video
_core:
- default_config_hash: ICmLjt5WIfXzvtJX_YkRGdyKasNtsRCLGIjhuqkbCvw
+ default_config_hash: 07Od0-Y4xT12ZoyAWxsTuJ0u32DaNqma-0sjemx9Olo
id: media.remote_video.media_library
targetEntityType: media
bundle: remote_video
diff --git a/conf/cmi/core.entity_form_display.paragraph.from_library.default.yml b/conf/cmi/core.entity_form_display.paragraph.from_library.default.yml
index e0f5996e3..2a6554609 100644
--- a/conf/cmi/core.entity_form_display.paragraph.from_library.default.yml
+++ b/conf/cmi/core.entity_form_display.paragraph.from_library.default.yml
@@ -7,6 +7,7 @@ dependencies:
- paragraphs.paragraphs_type.from_library
module:
- select2
+ - paragraphs_library
_core:
default_config_hash: RBhuX9npNnq2pmFG3bnj9977tRJQYZ1VTb45-BHjmqE
id: paragraph.from_library.default
diff --git a/conf/cmi/core.entity_form_display.paragraph.news_list.default.yml b/conf/cmi/core.entity_form_display.paragraph.news_list.default.yml
index d630adeca..ffaff7056 100644
--- a/conf/cmi/core.entity_form_display.paragraph.news_list.default.yml
+++ b/conf/cmi/core.entity_form_display.paragraph.news_list.default.yml
@@ -15,7 +15,7 @@ dependencies:
- select2
- text
_core:
- default_config_hash: qWEWZZ5y2CFa0KrsVWs0SgVKuOKv3M-yRvPSLqNqiE4
+ default_config_hash: o9SMPuB22qt8yDE6vhZ1eXIIcS2ztzFjZiidMrswmCU
id: paragraph.news_list.default
targetEntityType: paragraph
bundle: news_list
diff --git a/conf/cmi/core.entity_view_display.media.file.media_library.yml b/conf/cmi/core.entity_view_display.media.file.media_library.yml
index 0b118bb3d..ed6d8deb4 100644
--- a/conf/cmi/core.entity_view_display.media.file.media_library.yml
+++ b/conf/cmi/core.entity_view_display.media.file.media_library.yml
@@ -10,7 +10,7 @@ dependencies:
module:
- image
_core:
- default_config_hash: E6bdvTtEOpUnVMOmE-Zrnsb91guXE-JLQrL-Vx1q954
+ default_config_hash: PGilb0gSRJYPI4L3JcMoiR-sZ4GnWGA594CtYJXWzFk
id: media.file.media_library
targetEntityType: media
bundle: file
diff --git a/conf/cmi/core.entity_view_display.media.hel_map.media_library.yml b/conf/cmi/core.entity_view_display.media.hel_map.media_library.yml
index ee5c9a660..e1f554d60 100644
--- a/conf/cmi/core.entity_view_display.media.hel_map.media_library.yml
+++ b/conf/cmi/core.entity_view_display.media.hel_map.media_library.yml
@@ -9,7 +9,7 @@ dependencies:
module:
- helfi_media_map
_core:
- default_config_hash: xrAnYtkc8F-kZb6szt7sZHZ01BM1RnD-NfJ0bOtBTDs
+ default_config_hash: Z8YHS_atwbA0gO2P3uNNSbok6LicCJGZ5PNIM86COi0
id: media.hel_map.media_library
targetEntityType: media
bundle: hel_map
diff --git a/conf/cmi/core.entity_view_display.media.helfi_chart.media_library.yml b/conf/cmi/core.entity_view_display.media.helfi_chart.media_library.yml
index 02d79dfde..6dc1d41a8 100644
--- a/conf/cmi/core.entity_view_display.media.helfi_chart.media_library.yml
+++ b/conf/cmi/core.entity_view_display.media.helfi_chart.media_library.yml
@@ -11,7 +11,7 @@ dependencies:
module:
- helfi_media_chart
_core:
- default_config_hash: 28nwEZaRGXg0zD-nmyYusiqAx3gMir52iQG7f5pcyJM
+ default_config_hash: hR8QQbn1tM3s7PON49lzBRowMWmFCL-7gk8kpjXECQ0
id: media.helfi_chart.media_library
targetEntityType: media
bundle: helfi_chart
diff --git a/conf/cmi/core.entity_view_display.media.image.media_library.yml b/conf/cmi/core.entity_view_display.media.image.media_library.yml
index 224ec4770..636408173 100644
--- a/conf/cmi/core.entity_view_display.media.image.media_library.yml
+++ b/conf/cmi/core.entity_view_display.media.image.media_library.yml
@@ -11,7 +11,7 @@ dependencies:
module:
- image
_core:
- default_config_hash: yp1TP84E6TnK3NSxSikmnzowUx7XVkTQFxtOTe0KPfE
+ default_config_hash: v-wwjZUvAoDslCgLA5KMkZBkPglteYcy97uSy5Fl-io
id: media.image.media_library
targetEntityType: media
bundle: image
diff --git a/conf/cmi/core.entity_view_display.media.remote_video.media_library.yml b/conf/cmi/core.entity_view_display.media.remote_video.media_library.yml
index 93a466f20..5b950d581 100644
--- a/conf/cmi/core.entity_view_display.media.remote_video.media_library.yml
+++ b/conf/cmi/core.entity_view_display.media.remote_video.media_library.yml
@@ -11,7 +11,7 @@ dependencies:
module:
- image
_core:
- default_config_hash: '-OYhRJ3MUtZvvq8kso4SneprcI1fHAFW9QVpdL4L2hk'
+ default_config_hash: AodaWuCtx8vTnZ5Jtrp_8F-tNBrzZwlav62GAQhaMZs
id: media.remote_video.media_library
targetEntityType: media
bundle: remote_video
diff --git a/conf/cmi/core.entity_view_display.paragraph.news_list.default.yml b/conf/cmi/core.entity_view_display.paragraph.news_list.default.yml
index d2233696d..37d8b0f72 100644
--- a/conf/cmi/core.entity_view_display.paragraph.news_list.default.yml
+++ b/conf/cmi/core.entity_view_display.paragraph.news_list.default.yml
@@ -14,7 +14,7 @@ dependencies:
module:
- text
_core:
- default_config_hash: 8ae_31-J5VbYHZDB3yqQ03vR72k0To1dELDZEdOVYOQ
+ default_config_hash: gy6jtJHNETBeYxflDkbuoQDbkEZUTBdFlmmY5oRYfig
id: paragraph.news_list.default
targetEntityType: paragraph
bundle: news_list
diff --git a/conf/cmi/external_entities.external_entity_type.helfi_announcements.yml b/conf/cmi/external_entities.external_entity_type.helfi_announcements.yml
index f52cf89d9..4880ee6e2 100644
--- a/conf/cmi/external_entities.external_entity_type.helfi_announcements.yml
+++ b/conf/cmi/external_entities.external_entity_type.helfi_announcements.yml
@@ -5,7 +5,7 @@ dependencies:
module:
- helfi_etusivu_entities
_core:
- default_config_hash: 3JhNUZYN5TzmQVXkHRPLUGfc2s8hncoJD2wGyWgRzVM
+ default_config_hash: 2imB2uro181l7DLzY82D8LvGvDI5HFD3oKrB-9kgt94
id: helfi_announcements
label: 'Helfi: Announcements'
label_plural: 'Helfi: Announcements'
diff --git a/conf/cmi/external_entities.external_entity_type.helfi_news.yml b/conf/cmi/external_entities.external_entity_type.helfi_news.yml
index fdede9964..311270c3a 100644
--- a/conf/cmi/external_entities.external_entity_type.helfi_news.yml
+++ b/conf/cmi/external_entities.external_entity_type.helfi_news.yml
@@ -5,7 +5,7 @@ dependencies:
module:
- helfi_paragraphs_news_list
_core:
- default_config_hash: flMUKt27dw4Qq_U-20V4tWVrgpm-AcVby8KmaCBoXf8
+ default_config_hash: qHAP3KifdQVTgoHmLjzavIIuA0KK-jbKmmayodzLSaE
id: helfi_news
label: 'Helfi: News'
label_plural: 'Helfi: News'
diff --git a/conf/cmi/external_entities.external_entity_type.helfi_news_groups.yml b/conf/cmi/external_entities.external_entity_type.helfi_news_groups.yml
index b1366effe..3b8292e6c 100644
--- a/conf/cmi/external_entities.external_entity_type.helfi_news_groups.yml
+++ b/conf/cmi/external_entities.external_entity_type.helfi_news_groups.yml
@@ -5,7 +5,7 @@ dependencies:
module:
- helfi_paragraphs_news_list
_core:
- default_config_hash: qlDAzZQ8PSytgUjdqAXk-2_qmN_uLshxfOFF2ocfclI
+ default_config_hash: ktoTBmwQz_GKPFMjRFtQD3I2YnJDMy6kJgj4lLHZP5M
id: helfi_news_groups
label: 'Helfi: News groups'
label_plural: 'Helfi: News groups'
diff --git a/conf/cmi/external_entities.external_entity_type.helfi_news_neighbourhoods.yml b/conf/cmi/external_entities.external_entity_type.helfi_news_neighbourhoods.yml
index 54f636715..c7ce539fb 100644
--- a/conf/cmi/external_entities.external_entity_type.helfi_news_neighbourhoods.yml
+++ b/conf/cmi/external_entities.external_entity_type.helfi_news_neighbourhoods.yml
@@ -5,7 +5,7 @@ dependencies:
module:
- helfi_paragraphs_news_list
_core:
- default_config_hash: 9j2pKAqUWIeKOX6X5QLpOwFSDsezXFGX4Gyte8PXekY
+ default_config_hash: aVspV_NJZq1ZVwc8Yc3EkiFq_49Zo6qGsUME8me2kcc
id: helfi_news_neighbourhoods
label: 'Helfi: News neighbourhoods'
label_plural: 'Helfi: News neighbourhoods'
diff --git a/conf/cmi/external_entities.external_entity_type.helfi_news_tags.yml b/conf/cmi/external_entities.external_entity_type.helfi_news_tags.yml
index 8cc701b0a..158d9dfca 100644
--- a/conf/cmi/external_entities.external_entity_type.helfi_news_tags.yml
+++ b/conf/cmi/external_entities.external_entity_type.helfi_news_tags.yml
@@ -5,7 +5,7 @@ dependencies:
module:
- helfi_paragraphs_news_list
_core:
- default_config_hash: r7ZcjpivRV8Dr933oHre59xnKkzo7FA7BF85YoI0s24
+ default_config_hash: tHod6ZIsyIeXPIUplT4OH1cpZkxtqc3UhsFpNV_H3bQ
id: helfi_news_tags
label: 'Helfi: News tags'
label_plural: 'Helfi: News tags'
diff --git a/conf/cmi/external_entities.external_entity_type.helfi_surveys.yml b/conf/cmi/external_entities.external_entity_type.helfi_surveys.yml
index 2d280de89..5ab23035d 100644
--- a/conf/cmi/external_entities.external_entity_type.helfi_surveys.yml
+++ b/conf/cmi/external_entities.external_entity_type.helfi_surveys.yml
@@ -5,7 +5,7 @@ dependencies:
module:
- helfi_etusivu_entities
_core:
- default_config_hash: quOJapX57NowVd84rXbh7rHEJ-7csctd9FyWnQ7cIvk
+ default_config_hash: cOOBGsMZIwgp3zOCS0SsA3TwDpEJqmM6pVb0fTCC80o
id: helfi_surveys
label: 'Helfi: Survey'
label_plural: 'Helfi: Surveys'
diff --git a/conf/cmi/field.field.node.announcement.body.yml b/conf/cmi/field.field.node.announcement.body.yml
index d89163725..fa0887bb8 100644
--- a/conf/cmi/field.field.node.announcement.body.yml
+++ b/conf/cmi/field.field.node.announcement.body.yml
@@ -9,7 +9,7 @@ dependencies:
module:
- text
_core:
- default_config_hash: WvleFfpLbnQtIUacO3xu0rwNYfRDfAY4CbvmwE1B9ag
+ default_config_hash: OijFS0n0SdsLLMnAS0Z4SUa_GBz5mgplPGglXf5Vd-s
id: node.announcement.body
field_name: body
entity_type: node
diff --git a/conf/cmi/field.field.node.survey.body.yml b/conf/cmi/field.field.node.survey.body.yml
index e0cfdd809..cb77844d3 100644
--- a/conf/cmi/field.field.node.survey.body.yml
+++ b/conf/cmi/field.field.node.survey.body.yml
@@ -9,7 +9,7 @@ dependencies:
module:
- text
_core:
- default_config_hash: b0mXl8TINgWLn5XgnqShu90a4YKPYoiv8cKuu6ybhAU
+ default_config_hash: TMWUAj5DkOv1_BzrBAfbe9j2g4eOcRrINB4_F3pkpOo
id: node.survey.body
field_name: body
entity_type: node
diff --git a/conf/cmi/helfi_api_base.features.yml b/conf/cmi/helfi_api_base.features.yml
index 8ae0455e9..708189cda 100644
--- a/conf/cmi/helfi_api_base.features.yml
+++ b/conf/cmi/helfi_api_base.features.yml
@@ -1,5 +1,6 @@
disable_email_sending: true
disable_user_password: true
user_expire: true
+user_delete: true
use_mock_responses: false
logger: true
diff --git a/conf/cmi/language/ru/views.view.content.yml b/conf/cmi/language/ru/views.view.content.yml
index fb69671ec..85d9fcb4a 100644
--- a/conf/cmi/language/ru/views.view.content.yml
+++ b/conf/cmi/language/ru/views.view.content.yml
@@ -57,6 +57,8 @@ display:
group_items:
1:
title: Опубликовано
+ 2:
+ title: 'Снято с публикации'
langcode:
expose:
label: Язык
diff --git a/conf/cmi/media.type.image.yml b/conf/cmi/media.type.image.yml
index b21822a31..b114fff20 100644
--- a/conf/cmi/media.type.image.yml
+++ b/conf/cmi/media.type.image.yml
@@ -8,7 +8,7 @@ third_party_settings:
crop:
image_field: _none
_core:
- default_config_hash: LX01N5rjJ7mTGbJeTSQJuX_ZvFCUl0sCBkxSR3a18Bg
+ default_config_hash: h9Q6cJbRkDQMf9GnvrXshX0KsKXwEz7BhMrgZpbFuzU
id: image
label: Image
description: 'Use local image for reusable media.'
diff --git a/conf/cmi/search_api.index.paikkatieto_street_names.yml b/conf/cmi/search_api.index.paikkatieto_street_names.yml
new file mode 100644
index 000000000..5ff0415ef
--- /dev/null
+++ b/conf/cmi/search_api.index.paikkatieto_street_names.yml
@@ -0,0 +1,37 @@
+uuid: 3809159c-46bf-43d9-8496-823ce93efac4
+langcode: en
+status: true
+dependencies:
+ config:
+ - search_api.server.default
+ module:
+ - helfi_kymp_content
+ - helfi_react_search
+ - helfi_recommendations
+id: paikkatieto_street_names
+name: 'Paikkatieto street names'
+description: 'Street names from Paikkatieto API for vehicle removal search autocomplete.'
+read_only: false
+field_settings:
+ id:
+ label: ID
+ datasource_id: paikkatieto_street_name_source
+ property_path: id
+ type: string
+ street_name:
+ label: 'Street name'
+ datasource_id: paikkatieto_street_name_source
+ property_path: street_name
+ type: text
+datasource_settings:
+ paikkatieto_street_name_source: { }
+processor_settings: { }
+tracker_settings:
+ default:
+ indexing_order: fifo
+options:
+ cron_limit: 500
+ delete_on_fail: true
+ index_directly: false
+ track_changes_in_references: true
+server: default
diff --git a/docker/openshift/crons/street-data.sh b/docker/openshift/crons/street-data.sh
index 2973b3611..0d4647ed6 100644
--- a/docker/openshift/crons/street-data.sh
+++ b/docker/openshift/crons/street-data.sh
@@ -5,5 +5,6 @@ echo "Start indexing street data from external datasource: $(date)"
while true
do
drush sapi-r street_data && drush sapi-i street_data --batch-size=500
+ drush sapi-r paikkatieto_street_names
sleep 86400
done
diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
new file mode 100644
index 000000000..a20d7dafb
--- /dev/null
+++ b/phpstan-baseline.neon
@@ -0,0 +1,393 @@
+parameters:
+ ignoreErrors:
+ -
+ message: "#^Function _helfi_kymp_content_create_district_nodes_from_taxonomy_terms\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/helfi_kymp_content.module
+
+ -
+ message: "#^Function _helfi_kymp_content_invalidate_subdistricts\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/helfi_kymp_content.module
+
+ -
+ message: "#^Function helfi_kymp_content_first_paragraph_grey_alter\\(\\) has parameter \\$paragraphs with no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/helfi_kymp_content.module
+
+ -
+ message: "#^Function helfi_kymp_content_form_node_form_alter\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/helfi_kymp_content.module
+
+ -
+ message: "#^Function helfi_kymp_content_form_node_form_alter\\(\\) has parameter \\$form with no type specified\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/helfi_kymp_content.module
+
+ -
+ message: "#^Function helfi_kymp_content_form_node_form_alter\\(\\) has parameter \\$form_id with no type specified\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/helfi_kymp_content.module
+
+ -
+ message: "#^Function helfi_kymp_content_helfi_paragraph_types\\(\\) return type has no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/helfi_kymp_content.module
+
+ -
+ message: "#^Function helfi_kymp_content_node_delete\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/helfi_kymp_content.module
+
+ -
+ message: "#^Function helfi_kymp_content_node_form_validate\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/helfi_kymp_content.module
+
+ -
+ message: "#^Function helfi_kymp_content_node_form_validate\\(\\) has parameter \\$form with no type specified\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/helfi_kymp_content.module
+
+ -
+ message: "#^Function helfi_kymp_content_node_insert\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/helfi_kymp_content.module
+
+ -
+ message: "#^Function helfi_kymp_content_node_update\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/helfi_kymp_content.module
+
+ -
+ message: "#^Function helfi_kymp_content_preprocess_page\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/helfi_kymp_content.module
+
+ -
+ message: "#^Function helfi_kymp_content_preprocess_page\\(\\) has parameter \\$variables with no type specified\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/helfi_kymp_content.module
+
+ -
+ message: "#^Function helfi_kymp_content_sidebar_menu_visibility\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/helfi_kymp_content.module
+
+ -
+ message: "#^Function helfi_kymp_content_sidebar_menu_visibility\\(\\) has parameter \\$variables with no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/helfi_kymp_content.module
+
+ -
+ message: "#^Function helfi_kymp_content_sidebar_visibility_allowed_entities_alter\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/helfi_kymp_content.module
+
+ -
+ message: "#^Function helfi_kymp_content_sidebar_visibility_allowed_entities_alter\\(\\) has parameter \\$entities with no type specified\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/helfi_kymp_content.module
+
+ -
+ message: "#^Function helfi_kymp_content_theme\\(\\) return type has no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/helfi_kymp_content.module
+
+ -
+ message: "#^Method Drupal\\\\helfi_kymp_content\\\\DistrictUtility\\:\\:getSubdistrictParentIds\\(\\) return type has no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/DistrictUtility.php
+
+ -
+ message: "#^Method Drupal\\\\helfi_kymp_content\\\\Form\\\\SettingsForm\\:\\:buildForm\\(\\) has parameter \\$form with no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/Form/SettingsForm.php
+
+ -
+ message: "#^Method Drupal\\\\helfi_kymp_content\\\\Form\\\\SettingsForm\\:\\:buildForm\\(\\) return type has no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/Form/SettingsForm.php
+
+ -
+ message: "#^Method Drupal\\\\helfi_kymp_content\\\\Form\\\\SettingsForm\\:\\:getEditableConfigNames\\(\\) return type has no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/Form/SettingsForm.php
+
+ -
+ message: "#^Method Drupal\\\\helfi_kymp_content\\\\Form\\\\SettingsForm\\:\\:submitForm\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/Form/SettingsForm.php
+
+ -
+ message: "#^Method Drupal\\\\helfi_kymp_content\\\\Form\\\\SettingsForm\\:\\:submitForm\\(\\) has parameter \\$form with no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/Form/SettingsForm.php
+
+ -
+ message: "#^Method Drupal\\\\helfi_kymp_content\\\\Form\\\\SettingsForm\\:\\:validateForm\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/Form/SettingsForm.php
+
+ -
+ message: "#^Method Drupal\\\\helfi_kymp_content\\\\Form\\\\SettingsForm\\:\\:validateForm\\(\\) has parameter \\$form with no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/Form/SettingsForm.php
+
+ -
+ message: "#^Method Drupal\\\\helfi_kymp_content\\\\Hook\\\\MobileNoteCronHooks\\:\\:syncIndex\\(\\) has parameter \\$activeIds with no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/Hook/MobileNoteCronHooks.php
+
+ -
+ message: "#^Method Drupal\\\\helfi_kymp_content\\\\Hook\\\\MobileNoteCronHooks\\:\\:syncIndex\\(\\) has parameter \\$data with no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/Hook/MobileNoteCronHooks.php
+
+ -
+ message: "#^Method Drupal\\\\helfi_kymp_content\\\\Hook\\\\MobileNoteCronHooks\\:\\:syncIndex\\(\\) has parameter \\$expiredIds with no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/Hook/MobileNoteCronHooks.php
+
+ -
+ message: "#^Cannot access offset 'features' on array\\|bool\\|float\\|int\\|object\\|string\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/MobileNoteDataService.php
+
+ -
+ message: "#^Method Drupal\\\\helfi_kymp_content\\\\MobileNoteDataService\\:\\:buildMapUrl\\(\\) has parameter \\$coordinates with no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/MobileNoteDataService.php
+
+ -
+ message: "#^Method Drupal\\\\helfi_kymp_content\\\\MobileNoteDataService\\:\\:convertGeometry\\(\\) has parameter \\$geometry with no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/MobileNoteDataService.php
+
+ -
+ message: "#^Method Drupal\\\\helfi_kymp_content\\\\MobileNoteDataService\\:\\:transformFeature\\(\\) has parameter \\$feature with no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/MobileNoteDataService.php
+
+
+
+ -
+ message: "#^Method Drupal\\\\helfi_kymp_content\\\\Plugin\\\\Block\\\\SubdistrictsNavigationBlock\\:\\:__construct\\(\\) has parameter \\$configuration with no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/Plugin/Block/SubdistrictsNavigationBlock.php
+
+ -
+ message: "#^Method Drupal\\\\helfi_kymp_content\\\\Plugin\\\\Block\\\\SubdistrictsNavigationBlock\\:\\:build\\(\\) return type has no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/Plugin/Block/SubdistrictsNavigationBlock.php
+
+ -
+ message: "#^Method Drupal\\\\helfi_kymp_content\\\\Plugin\\\\Block\\\\SubdistrictsNavigationBlock\\:\\:create\\(\\) has parameter \\$configuration with no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/Plugin/Block/SubdistrictsNavigationBlock.php
+
+ -
+ message: "#^Method Drupal\\\\helfi_kymp_content\\\\Plugin\\\\Block\\\\VehicleRemovalBlock\\:\\:__construct\\(\\) has parameter \\$configuration with no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/Plugin/Block/VehicleRemovalBlock.php
+
+ -
+ message: "#^Method Drupal\\\\helfi_kymp_content\\\\Plugin\\\\Block\\\\VehicleRemovalBlock\\:\\:build\\(\\) return type has no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/Plugin/Block/VehicleRemovalBlock.php
+
+ -
+ message: "#^Method Drupal\\\\helfi_kymp_content\\\\Plugin\\\\DataType\\\\MobileNoteData\\:\\:propertyDefinitions\\(\\) return type has no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/Plugin/DataType/MobileNoteData.php
+
+ -
+ message: "#^Method Drupal\\\\helfi_kymp_content\\\\Plugin\\\\DataType\\\\StreetData\\:\\:propertyDefinitions\\(\\) return type has no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/Plugin/DataType/StreetData.php
+
+ -
+ message: "#^Cannot access offset 'id' on Drupal\\\\Core\\\\TypedData\\\\ComplexDataInterface\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/Plugin/search_api/datasource/HelfiStreetDataSource.php
+
+ -
+ message: "#^Method Drupal\\\\helfi_kymp_content\\\\Plugin\\\\search_api\\\\datasource\\\\HelfiStreetDataSource\\:\\:create\\(\\) has parameter \\$configuration with no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/Plugin/search_api/datasource/HelfiStreetDataSource.php
+
+ -
+ message: "#^Method Drupal\\\\helfi_kymp_content\\\\Plugin\\\\search_api\\\\datasource\\\\HelfiStreetDataSource\\:\\:loadMultiple\\(\\) has parameter \\$ids with no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/Plugin/search_api/datasource/HelfiStreetDataSource.php
+
+ -
+ message: "#^Cannot access offset 'id' on Drupal\\\\Core\\\\TypedData\\\\ComplexDataInterface\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/Plugin/search_api/datasource/MobileNoteDataSource.php
+
+ -
+ message: "#^Method Drupal\\\\helfi_kymp_content\\\\Plugin\\\\search_api\\\\datasource\\\\MobileNoteDataSource\\:\\:create\\(\\) has parameter \\$configuration with no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/Plugin/search_api/datasource/MobileNoteDataSource.php
+
+ -
+ message: "#^Method Drupal\\\\helfi_kymp_content\\\\Plugin\\\\search_api\\\\datasource\\\\MobileNoteDataSource\\:\\:loadMultiple\\(\\) has parameter \\$ids with no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/Plugin/search_api/datasource/MobileNoteDataSource.php
+
+ -
+ message: "#^Property Drupal\\\\Core\\\\TypedData\\\\ComplexDataDefinitionBase\\:\\:\\$propertyDefinitions \\(array\\\\) in isset\\(\\) is not nullable\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/TypedData/MobileNoteDataDefinition.php
+
+ -
+ message: "#^Property Drupal\\\\Core\\\\TypedData\\\\ComplexDataDefinitionBase\\:\\:\\$propertyDefinitions \\(array\\\\) in isset\\(\\) is not nullable\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/src/TypedData/StreetDataDefinition.php
+
+ -
+ message: "#^Method Drupal\\\\Tests\\\\helfi_kymp_content\\\\Kernel\\\\MobileNoteCronHooksTest\\:\\:createMockIndex\\(\\) has parameter \\$staleItemIds with no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/tests/src/Kernel/MobileNoteCronHooksTest.php
+
+ -
+ message: "#^Method Drupal\\\\Tests\\\\helfi_kymp_content\\\\Kernel\\\\MobileNoteCronHooksTest\\:\\:createMockIndex\\(\\) return type with generic class Prophecy\\\\Prophecy\\\\ObjectProphecy does not specify its types\\: T$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/tests/src/Kernel/MobileNoteCronHooksTest.php
+
+ -
+ message: "#^Parameter \\$body of class GuzzleHttp\\\\Psr7\\\\Response constructor expects Psr\\\\Http\\\\Message\\\\StreamInterface\\|resource\\|string\\|null, string\\|false given\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/tests/src/Kernel/MobileNoteCronHooksTest.php
+
+ -
+ message: "#^Parameter \\#3 \\$body of class GuzzleHttp\\\\Psr7\\\\Response constructor expects Psr\\\\Http\\\\Message\\\\StreamInterface\\|resource\\|string\\|null, string\\|false given\\.$#"
+ count: 3
+ path: public/modules/custom/helfi_kymp_content/tests/src/Kernel/MobileNoteDataServiceTest.php
+
+ -
+ message: "#^Parameter \\$body of class GuzzleHttp\\\\Psr7\\\\Response constructor expects Psr\\\\Http\\\\Message\\\\StreamInterface\\|resource\\|string\\|null, string\\|false given\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/tests/src/Kernel/MobileNoteDataSourceTest.php
+
+ -
+ message: "#^Parameter \\$body of class GuzzleHttp\\\\Psr7\\\\Response constructor expects Psr\\\\Http\\\\Message\\\\StreamInterface\\|resource\\|string\\|null, string\\|false given\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_content/tests/src/Kernel/StreetDataTest.php
+
+ -
+ message: "#^Function helfi_kymp_plans_preprocess_paragraph__list_of_plans\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_plans/helfi_kymp_plans.module
+
+ -
+ message: "#^Function helfi_kymp_plans_preprocess_paragraph__list_of_plans\\(\\) has parameter \\$variables with no type specified\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_plans/helfi_kymp_plans.module
+
+ -
+ message: "#^Function helfi_kymp_plans_theme\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_plans/helfi_kymp_plans.module
+
+ -
+ message: "#^Function helfi_kymp_plans_theme\\(\\) has parameter \\$existing with no type specified\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_plans/helfi_kymp_plans.module
+
+ -
+ message: "#^Function helfi_kymp_plans_theme\\(\\) has parameter \\$path with no type specified\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_plans/helfi_kymp_plans.module
+
+ -
+ message: "#^Function helfi_kymp_plans_theme\\(\\) has parameter \\$theme with no type specified\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_plans/helfi_kymp_plans.module
+
+ -
+ message: "#^Function helfi_kymp_plans_theme\\(\\) has parameter \\$type with no type specified\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_plans/helfi_kymp_plans.module
+
+ -
+ message: "#^Method Drupal\\\\helfi_kymp_plans\\\\ListOfPlans\\:\\:getPlans\\(\\) return type has no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_plans/src/ListOfPlans.php
+
+ -
+ message: "#^Parameter \\#2 \\$timestamp of function date expects int\\|null, int\\|false given\\.$#"
+ count: 1
+ path: public/modules/custom/helfi_kymp_plans/src/ListOfPlans.php
+
+ -
+ message: "#^Function hdbt_subtheme_preprocess_block\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: public/themes/custom/hdbt_subtheme/hdbt_subtheme.theme
+
+ -
+ message: "#^Function hdbt_subtheme_preprocess_block\\(\\) has parameter \\$variables with no type specified\\.$#"
+ count: 1
+ path: public/themes/custom/hdbt_subtheme/hdbt_subtheme.theme
+
+ -
+ message: "#^Function hdbt_subtheme_preprocess_node\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: public/themes/custom/hdbt_subtheme/hdbt_subtheme.theme
+
+ -
+ message: "#^Function hdbt_subtheme_preprocess_node\\(\\) has parameter \\$variables with no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/themes/custom/hdbt_subtheme/hdbt_subtheme.theme
+
+ -
+ message: "#^Function hdbt_subtheme_preprocess_paragraph__journey_planner\\(\\) has parameter \\$variables with no value type specified in iterable type array\\.$#"
+ count: 1
+ path: public/themes/custom/hdbt_subtheme/hdbt_subtheme.theme
+
+ -
+ message: "#^Function hdbt_subtheme_preprocess_paragraph__project_listing\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: public/themes/custom/hdbt_subtheme/hdbt_subtheme.theme
+
+ -
+ message: "#^Function hdbt_subtheme_preprocess_paragraph__project_listing\\(\\) has parameter \\$variables with no type specified\\.$#"
+ count: 1
+ path: public/themes/custom/hdbt_subtheme/hdbt_subtheme.theme
+
+ -
+ message: "#^Function hdbt_subtheme_preprocess_views_view__project_list\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: public/themes/custom/hdbt_subtheme/hdbt_subtheme.theme
+
+ -
+ message: "#^Function hdbt_subtheme_preprocess_views_view__project_list\\(\\) has parameter \\$variables with no type specified\\.$#"
+ count: 1
+ path: public/themes/custom/hdbt_subtheme/hdbt_subtheme.theme
+
+ -
+ message: "#^Function hdbt_subtheme_theme_suggestions_block_alter\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: public/themes/custom/hdbt_subtheme/hdbt_subtheme.theme
+
+ -
+ message: "#^Function hdbt_subtheme_theme_suggestions_block_alter\\(\\) has parameter \\$suggestions with no type specified\\.$#"
+ count: 1
+ path: public/themes/custom/hdbt_subtheme/hdbt_subtheme.theme
+
+ -
+ message: "#^Function hdbt_subtheme_theme_suggestions_menu_alter\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: public/themes/custom/hdbt_subtheme/hdbt_subtheme.theme
+
+ -
+ message: "#^Function hdbt_subtheme_theme_suggestions_menu_alter\\(\\) has parameter \\$suggestions with no type specified\\.$#"
+ count: 1
+ path: public/themes/custom/hdbt_subtheme/hdbt_subtheme.theme
+
+ -
+ message: "#^Function hdbt_subtheme_theme_suggestions_menu_alter\\(\\) has parameter \\$variables with no type specified\\.$#"
+ count: 1
+ path: public/themes/custom/hdbt_subtheme/hdbt_subtheme.theme
diff --git a/phpstan.neon b/phpstan.neon
index 5755a2aa6..8a0d88d82 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -1,3 +1,5 @@
+includes:
+ - phpstan-baseline.neon
parameters:
fileExtensions:
- php
@@ -9,5 +11,5 @@ parameters:
- ./public/themes/custom
excludePaths:
- vendor
- level: 3
+ level: 7
treatPhpDocTypesAsCertain: false
diff --git a/public/modules/custom/helfi_kymp_content/config/schema/helfi_kymp_content.schema.yml b/public/modules/custom/helfi_kymp_content/config/schema/helfi_kymp_content.schema.yml
index 1807bc127..7c74f8959 100644
--- a/public/modules/custom/helfi_kymp_content/config/schema/helfi_kymp_content.schema.yml
+++ b/public/modules/custom/helfi_kymp_content/config/schema/helfi_kymp_content.schema.yml
@@ -21,3 +21,9 @@ helfi_kymp_content.settings:
type: string
sync_lookback_offset:
type: string
+ address_search_distance:
+ type: integer
+ label: 'Address search distance in meters'
+ address_search_limit:
+ type: integer
+ label: 'Address search result limit'
diff --git a/public/modules/custom/helfi_kymp_content/helfi_kymp_content.services.yml b/public/modules/custom/helfi_kymp_content/helfi_kymp_content.services.yml
index 990c84f0a..2f63e2ec4 100644
--- a/public/modules/custom/helfi_kymp_content/helfi_kymp_content.services.yml
+++ b/public/modules/custom/helfi_kymp_content/helfi_kymp_content.services.yml
@@ -8,12 +8,6 @@ services:
arguments:
- 'helfi_kymp_content'
- helfi_kymp_content.search_api_subscriber:
- class: Drupal\helfi_kymp_content\EventSubscriber\SearchApiSubscriber
- arguments: ['@logger.channel.helfi_kymp_content']
- tags:
- - { name: event_subscriber }
-
Drupal\helfi_kymp_content\StreetDataService: ~
Drupal\helfi_kymp_content\Paikkatieto\PaikkatietoClient: ~
diff --git a/public/modules/custom/helfi_kymp_content/src/EventSubscriber/SearchApiSubscriber.php b/public/modules/custom/helfi_kymp_content/src/EventSubscriber/SearchApiSubscriber.php
deleted file mode 100644
index 08bdfbcac..000000000
--- a/public/modules/custom/helfi_kymp_content/src/EventSubscriber/SearchApiSubscriber.php
+++ /dev/null
@@ -1,77 +0,0 @@
- ['reindex'],
- ];
- }
-
- /**
- * Tell tracker which IDs to index on next indexing.
- *
- * @param \Drupal\search_api\Event\ReindexScheduledEvent $event
- * The event.
- *
- * @throws \Drupal\search_api\SearchApiException
- */
- public function reindex(ReindexScheduledEvent $event): void {
- $index = $event->getIndex();
-
- // Handle street_data index.
- if ($index->id() == 'street_data') {
- $this->trackDatasourceItems($index, 'helfi_street_data_source');
- }
- }
-
- /**
- * Track items for a datasource.
- *
- * @param \Drupal\search_api\IndexInterface $index
- * The index.
- * @param string $datasourceId
- * The datasource ID.
- */
- protected function trackDatasourceItems($index, string $datasourceId): void {
- try {
- $source = $index->getDatasource($datasourceId);
- $ids = $source->getItemIds();
- if (!$ids) {
- return;
- }
- $index->trackItemsInserted($source->getPluginId(), $ids);
- }
- catch (\Exception $e) {
- $this->logger->error('Unable to fetch data while running reindex event for @datasource: @message', [
- '@datasource' => $datasourceId,
- '@message' => $e->getMessage(),
- ]);
- }
- }
-
-}
diff --git a/public/modules/custom/helfi_kymp_content/src/Paikkatieto/PaikkatietoClient.php b/public/modules/custom/helfi_kymp_content/src/Paikkatieto/PaikkatietoClient.php
index 70c694bda..fafa7e846 100644
--- a/public/modules/custom/helfi_kymp_content/src/Paikkatieto/PaikkatietoClient.php
+++ b/public/modules/custom/helfi_kymp_content/src/Paikkatieto/PaikkatietoClient.php
@@ -21,11 +21,6 @@ class PaikkatietoClient implements LoggerAwareInterface {
use LoggerAwareTrait;
- /**
- * Earth radius in meters.
- */
- private const float EARTH_RADIUS = 6371000;
-
public function __construct(
private readonly ConfigFactoryInterface $configFactory,
private readonly ClientInterface $httpClient,
@@ -36,23 +31,19 @@ public function __construct(
* Fetches unique street names along a linestring.
*
* Queries the API at the midpoint of each segment and returns
- * the deduplicated set of closest street names.
+ * the deduplicated set of street names found within the configured
+ * search radius.
*
- * We attempt to avoid picking the wrong results at an intersection
- * by choosing midpoints.
- *
- * @param array $coordinates
+ * @param array $coordinates
* Array of [lon, lat] coordinate pairs (GeoJSON order).
- * @param int $distance
- * Search radius in meters for each segment midpoint.
*
- * @return array
+ * @return array
* Unique street names (fi and sv) found along the linestring.
*
* @throws \Drupal\helfi_kymp_content\Paikkatieto\Exception
* @throws \InvalidArgumentException
*/
- public function fetchStreetsForLineString(array $coordinates, int $distance = 75): array {
+ public function fetchStreetsForLineString(array $coordinates): array {
$count = count($coordinates);
$streets = [];
@@ -60,7 +51,7 @@ public function fetchStreetsForLineString(array $coordinates, int $distance = 75
$midLat = ($coordinates[$i][1] + $coordinates[$i + 1][1]) / 2;
$midLon = ($coordinates[$i][0] + $coordinates[$i + 1][0]) / 2;
- $segmentStreets = $this->fetchStreetsByPoint($midLat, $midLon, $distance);
+ $segmentStreets = $this->fetchStreetsByPoint($midLat, $midLon);
array_push($streets, ...$segmentStreets);
}
@@ -70,78 +61,119 @@ public function fetchStreetsForLineString(array $coordinates, int $distance = 75
/**
* Fetches street names using the point-radius method.
*
+ * Returns all unique street names found within the configured search
+ * radius, not just the closest. The search distance and result limit
+ * are read from 'helfi_kymp_content.settings' config
+ * (address_search_distance, address_search_limit) with defaults of
+ * 75 meters and 20 results.
+ *
* @param float $lat
* Latitude.
* @param float $lon
* Longitude.
- * @param int $distance
- * Distance. We look at street names within this
- * distance and pick the closest result.
*
- * @return array
+ * @return array
* A list of unique street names found within radius.
*
* @throws \Drupal\helfi_kymp_content\Paikkatieto\Exception
* @throws \InvalidArgumentException
*/
- public function fetchStreetsByPoint(float $lat, float $lon, int $distance = 75): array {
- $results = $this->makeRequest([
+ public function fetchStreetsByPoint(float $lat, float $lon): array {
+ $config = $this->configFactory->get('helfi_kymp_content.settings');
+ $distance = $config->get('address_search_distance') ?: 75;
+ $limit = $config->get('address_search_limit') ?: 20;
+
+ $data = $this->makeRequest([
'lat' => $lat,
'lon' => $lon,
'distance' => $distance,
- 'limit' => 20,
+ 'limit' => $limit,
]);
+ $results = $data->results ?? [];
if (empty($results)) {
return [];
}
- // Find the closest result by haversine distance.
- $closest = NULL;
- $minDistance = PHP_FLOAT_MAX;
-
+ $streets = [];
foreach ($results as $result) {
- $coords = $result->location->coordinates ?? NULL;
- if (!$coords) {
- continue;
- }
- // API returns [lon, lat] (GeoJSON order).
- $d = self::haversineDistance($lat, $lon, $coords[1], $coords[0]);
- if ($d < $minDistance) {
- $minDistance = $d;
- $closest = $result;
+ foreach (['fi', 'sv'] as $langcode) {
+ if (!empty($result->street->name->{$langcode})) {
+ $streets[] = $result->street->name->{$langcode};
+ }
}
}
- if (!$closest) {
- return [];
+ return array_values(array_unique($streets));
+ }
+
+ /**
+ * Fetches unique street names from a single page of the API.
+ *
+ * @param int $page
+ * The 1-based page number.
+ * @param int $pageSize
+ * Results per page.
+ *
+ * @return array|null
+ * List of street names with their language, or NULL past the last page.
+ *
+ * @throws \Drupal\helfi_kymp_content\Paikkatieto\Exception
+ * @throws \InvalidArgumentException
+ */
+ public function fetchStreetNamesByPage(int $page = 1, int $pageSize = 500): ?array {
+ try {
+ $data = $this->makeRequest([
+ 'municipality' => 'Helsinki',
+ 'page_size' => $pageSize,
+ 'page' => $page,
+ ]);
+ }
+ catch (Exception $e) {
+ // API returns 404 {"detail":"Epäkelpo sivu."} past the last page.
+ $previous = $e->getPrevious();
+ if ($previous instanceof RequestException && $previous->getResponse()?->getStatusCode() === 404) {
+ return NULL;
+ }
+
+ throw $e;
}
+ $results = $data->results ?? [];
$streets = [];
- foreach (['fi', 'sv'] as $langcode) {
- if (!empty($closest->street->name->{$langcode})) {
- $streets[] = $closest->street->name->{$langcode};
+
+ foreach ($results as $result) {
+ foreach (['fi', 'sv', 'en'] as $langcode) {
+ $name = $result->street->name->{$langcode} ?? NULL;
+ if (!empty($name)) {
+ $streets[] = ['name' => $name, 'language' => $langcode];
+ }
}
}
+ $this->logger?->info('Paikkatieto street names: fetched page @page (@count results).', [
+ '@page' => $page,
+ '@count' => count($results),
+ ]);
+
return $streets;
}
/**
- * Fetches results from the Paikkatietohaku API.
+ * Fetches a response from the Paikkatietohaku API.
*
- * @param array $queryParams
+ * @param array $queryParams
* Query parameters for the API request.
* @param int $maxRetries
* Maximum number of retries on 502 errors.
*
- * @return array
- * The results array from the API response.
+ * @return object
+ * The full decoded JSON response.
*
* @throws \Drupal\helfi_kymp_content\Paikkatieto\Exception
* @throws \InvalidArgumentException
*/
- private function makeRequest(array $queryParams, int $maxRetries = 3): array {
+ private function makeRequest(array $queryParams, int $maxRetries = 3): object {
$config = $this->configFactory->get('helfi_kymp_content.settings');
$apiKey = $config->get('address_api_key');
@@ -164,9 +196,9 @@ private function makeRequest(array $queryParams, int $maxRetries = 3): array {
'timeout' => 60,
]);
+ /** @var object $data */
$data = Utils::jsonDecode($response->getBody()->getContents());
-
- return $data->results ?? [];
+ return $data;
}
catch (GuzzleException $e) {
$lastException = $e;
@@ -187,24 +219,4 @@ private function makeRequest(array $queryParams, int $maxRetries = 3): array {
throw new Exception($lastException->getMessage(), previous: $lastException);
}
- /**
- * Calculate the distance between two coordinates using the Haversine formula.
- */
- private static function haversineDistance(float $lat1, float $lon1, float $lat2, float $lon2): float {
- $lat1 = deg2rad($lat1);
- $lon1 = deg2rad($lon1);
- $lat2 = deg2rad($lat2);
- $lon2 = deg2rad($lon2);
-
- $deltaLat = $lat2 - $lat1;
- $deltaLon = $lon2 - $lon1;
-
- $a = sin($deltaLat / 2) ** 2
- + cos($lat1) * cos($lat2) * sin($deltaLon / 2) ** 2;
-
- $c = 2 * atan2(sqrt($a), sqrt(1 - $a));
-
- return self::EARTH_RADIUS * $c;
- }
-
}
diff --git a/public/modules/custom/helfi_kymp_content/src/Plugin/DataType/PaikkatietoStreetName.php b/public/modules/custom/helfi_kymp_content/src/Plugin/DataType/PaikkatietoStreetName.php
new file mode 100644
index 000000000..c2d67abfe
--- /dev/null
+++ b/public/modules/custom/helfi_kymp_content/src/Plugin/DataType/PaikkatietoStreetName.php
@@ -0,0 +1,48 @@
+
+ * The property definitions.
+ */
+ public static function propertyDefinitions(): array {
+ $properties = [];
+
+ $properties['id'] = DataDefinition::create('string')
+ ->setLabel('ID')
+ ->setRequired(TRUE);
+
+ $properties['street_name'] = DataDefinition::create('string')
+ ->setLabel('Street name')
+ ->setRequired(TRUE);
+
+ $properties['language'] = DataDefinition::create('string')
+ ->setLabel('Language')
+ ->setRequired(TRUE);
+
+ return $properties;
+ }
+
+}
diff --git a/public/modules/custom/helfi_kymp_content/src/Plugin/search_api/datasource/PaikkatietoStreetNameDataSource.php b/public/modules/custom/helfi_kymp_content/src/Plugin/search_api/datasource/PaikkatietoStreetNameDataSource.php
new file mode 100644
index 000000000..81223a46a
--- /dev/null
+++ b/public/modules/custom/helfi_kymp_content/src/Plugin/search_api/datasource/PaikkatietoStreetNameDataSource.php
@@ -0,0 +1,142 @@
+ $configuration
+ */
+ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+ $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
+ $instance->client = $container->get(PaikkatietoClient::class);
+ $instance->typedDataManager = $container->get(TypedDataManagerInterface::class);
+ $instance->logger = $container->get('logger.channel.helfi_kymp_content');
+ return $instance;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getItemIds($page = NULL) {
+ // API pages are 1-based, datasource pages are 0-based.
+ $apiPage = ($page ?? 0) + 1;
+
+ try {
+ $results = $this->client->fetchStreetNamesByPage($apiPage);
+ }
+ catch (\InvalidArgumentException $e) {
+ Error::logException($this->logger, $e);
+ return NULL;
+ }
+
+ if ($results === NULL) {
+ return NULL;
+ }
+
+ $ids = [];
+ foreach ($results as $entry) {
+ $ids[] = "{$entry['language']}:{$entry['name']}";
+ }
+
+ // The API returns addresses, not unique street names, so the same
+ // street name appears multiple times per page. Duplicates within a
+ // single batch cause integrity constraint violations in the tracker.
+ return array_unique($ids);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getItemId(ComplexDataInterface $item): null|string {
+ return $item->get('id')->getString();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Item content is encoded in the ID. No network requests needed.
+ */
+ public function load($id): ?ComplexDataInterface {
+ [$language, $name] = explode(':', $id, 2);
+ $definition = $this->typedDataManager->createDataDefinition('paikkatieto_street_name');
+ $typedData = $this->typedDataManager->create($definition);
+ assert($typedData instanceof ComplexDataInterface);
+ $typedData->setValue([
+ 'id' => $id,
+ 'street_name' => $name,
+ 'language' => $language,
+ ]);
+
+ return $typedData;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @phpstan-param array $ids
+ */
+ public function loadMultiple(array $ids): array {
+ $items = [];
+
+ foreach ($ids as $id) {
+ $items[$id] = $this->load($id);
+ }
+
+ return $items;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getItemLanguage(ComplexDataInterface $item): string {
+ return $item->get('language')->getString();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPropertyDefinitions(): array {
+ return PaikkatietoStreetName::propertyDefinitions();
+ }
+
+}
diff --git a/public/modules/custom/helfi_kymp_content/src/TypedData/PaikkatietoStreetNameDefinition.php b/public/modules/custom/helfi_kymp_content/src/TypedData/PaikkatietoStreetNameDefinition.php
new file mode 100644
index 000000000..a4abb5d24
--- /dev/null
+++ b/public/modules/custom/helfi_kymp_content/src/TypedData/PaikkatietoStreetNameDefinition.php
@@ -0,0 +1,25 @@
+propertyDefinitions)) {
+ $this->propertyDefinitions = PaikkatietoStreetName::propertyDefinitions();
+ }
+ return $this->propertyDefinitions;
+ }
+
+}
diff --git a/public/modules/custom/helfi_kymp_content/tests/src/Kernel/MobileNoteDataServiceTest.php b/public/modules/custom/helfi_kymp_content/tests/src/Kernel/MobileNoteDataServiceTest.php
index 573b13bf6..7e1f80007 100644
--- a/public/modules/custom/helfi_kymp_content/tests/src/Kernel/MobileNoteDataServiceTest.php
+++ b/public/modules/custom/helfi_kymp_content/tests/src/Kernel/MobileNoteDataServiceTest.php
@@ -128,11 +128,12 @@ public function testGetMobileNoteData(): void {
$this->assertEquals('test.123', $item['id']);
$this->assertEquals('Test Street 1', $item['address']);
$this->assertEquals('Test Reason', $item['reason']);
- // Street names should contain the closest result's fi and sv names.
+ // Street names should contain all results' fi and sv names.
$this->assertNotEmpty($item['street_names']);
$this->assertContains('Mannerheimintie', $item['street_names']);
$this->assertContains('Mannerheimvägen', $item['street_names']);
- $this->assertCount(2, $item['street_names']);
+ $this->assertContains('Kaivokatu', $item['street_names']);
+ $this->assertCount(3, $item['street_names']);
// Verify date conversion (Europe/Helsinki timezone).
$tz = new \DateTimeZone('Europe/Helsinki');
diff --git a/public/modules/custom/helfi_kymp_content/tests/src/Kernel/PaikkatietoClientTest.php b/public/modules/custom/helfi_kymp_content/tests/src/Kernel/PaikkatietoClientTest.php
new file mode 100644
index 000000000..06b7313e0
--- /dev/null
+++ b/public/modules/custom/helfi_kymp_content/tests/src/Kernel/PaikkatietoClientTest.php
@@ -0,0 +1,226 @@
+config('helfi_kymp_content.settings')
+ ->set('address_api_key', 'TEST_KEY')
+ ->save();
+ }
+
+ /**
+ * Creates a PaikkatietoClient with mocked HTTP responses.
+ *
+ * @param array<\Psr\Http\Message\ResponseInterface|\GuzzleHttp\Exception\GuzzleException> $responses
+ * The queued HTTP responses.
+ *
+ * @return \Drupal\helfi_kymp_content\Paikkatieto\PaikkatietoClient
+ * The client.
+ */
+ private function createClient(array $responses): PaikkatietoClient {
+ $httpClient = $this->createMockHttpClient($responses);
+ $this->container->set('http_client', $httpClient);
+ return $this->container->get(PaikkatietoClient::class);
+ }
+
+ /**
+ * Creates an address API JSON response.
+ *
+ * @param array $streets
+ * Street names keyed by language.
+ *
+ * @return \GuzzleHttp\Psr7\Response
+ * A mock response.
+ */
+ private function createAddressResponse(array $streets): Response {
+ $results = [];
+ foreach ($streets as $names) {
+ $nameObj = new \stdClass();
+ foreach ($names as $lang => $name) {
+ $nameObj->{$lang} = $name;
+ }
+ $results[] = ['street' => ['name' => $nameObj]];
+ }
+ return new Response(body: json_encode(['results' => $results], JSON_THROW_ON_ERROR));
+ }
+
+ /**
+ * Tests fetching street names by point.
+ */
+ public function testFetchStreetsByPoint(): void {
+ $client = $this->createClient([
+ $this->createAddressResponse([
+ ['fi' => 'Mannerheimintie', 'sv' => 'Mannerheimvägen'],
+ ['fi' => 'Mannerheimintie', 'sv' => 'Mannerheimvägen'],
+ ['fi' => 'Kaivokatu', 'sv' => 'Brunnsgatan'],
+ ]),
+ new Response(body: json_encode(['results' => []], JSON_THROW_ON_ERROR)),
+ ]);
+
+ // Tests fetching street names by point.
+ $streets = $client->fetchStreetsByPoint(60.171, 24.941);
+
+ $this->assertCount(4, $streets);
+ $this->assertContains('Mannerheimintie', $streets);
+ $this->assertContains('Mannerheimvägen', $streets);
+ $this->assertContains('Kaivokatu', $streets);
+ $this->assertContains('Brunnsgatan', $streets);
+
+ // Tests fetching street names by point with empty results.
+ $streets = $client->fetchStreetsByPoint(60.191, 24.931);
+
+ $this->assertEmpty($streets);
+ }
+
+ /**
+ * Tests fetching streets for a linestring.
+ */
+ public function testFetchStreetsForLineString(): void {
+ $client = $this->createClient([
+ // Segment 1 midpoint response.
+ $this->createAddressResponse([
+ ['fi' => 'Mannerheimintie', 'sv' => 'Mannerheimvägen'],
+ ]),
+ // Segment 2 midpoint response.
+ $this->createAddressResponse([
+ ['fi' => 'Mannerheimintie', 'sv' => 'Mannerheimvägen'],
+ ['fi' => 'Kaivokatu'],
+ ]),
+ ]);
+
+ $coordinates = [
+ [24.941, 60.171],
+ [24.945, 60.173],
+ [24.950, 60.175],
+ ];
+
+ $streets = $client->fetchStreetsForLineString($coordinates);
+
+ // Deduplicated across segments.
+ $this->assertCount(3, $streets);
+ $this->assertContains('Mannerheimintie', $streets);
+ $this->assertContains('Mannerheimvägen', $streets);
+ $this->assertContains('Kaivokatu', $streets);
+ }
+
+ /**
+ * Tests fetching street names by page.
+ */
+ public function testFetchStreetNamesByPage(): void {
+ $client = $this->createClient([
+ $this->createAddressResponse([
+ ['fi' => 'Mannerheimintie', 'sv' => 'Mannerheimvägen'],
+ ['fi' => 'Kaivokatu'],
+ ]),
+ new RequestException(
+ 'Not Found',
+ new Request('GET', 'test'),
+ new Response(404, [], json_encode(['detail' => 'error'], JSON_THROW_ON_ERROR)),
+ ),
+ new RequestException(
+ 'Server Error',
+ new Request('GET', 'test'),
+ new Response(500),
+ ),
+ ]);
+
+ $results = $client->fetchStreetNamesByPage(1);
+
+ $this->assertNotNull($results);
+ $this->assertCount(3, $results);
+
+ $this->assertEquals('Mannerheimintie', $results[0]['name']);
+ $this->assertEquals('fi', $results[0]['language']);
+ $this->assertEquals('Mannerheimvägen', $results[1]['name']);
+ $this->assertEquals('sv', $results[1]['language']);
+ $this->assertEquals('Kaivokatu', $results[2]['name']);
+ $this->assertEquals('fi', $results[2]['language']);
+
+ // Tests that fetching past the last page returns NULL.
+ $result = $client->fetchStreetNamesByPage(999);
+ $this->assertNull($result);
+
+ // Tests that non-404 errors are rethrown.
+ $this->expectException(Exception::class);
+ $client->fetchStreetNamesByPage(1);
+ }
+
+ /**
+ * Tests that missing API key throws an exception.
+ */
+ public function testMissingApiKeyThrows(): void {
+ $this->config('helfi_kymp_content.settings')
+ ->set('address_api_key', '')
+ ->save();
+
+ $client = $this->createClient([]);
+
+ $this->expectException(\InvalidArgumentException::class);
+ $client->fetchStreetsByPoint(60.171, 24.941);
+ }
+
+ /**
+ * Tests retry on 502 followed by success.
+ */
+ public function testRetryOn502ThenSuccess(): void {
+ $client = $this->createClient([
+ new RequestException(
+ 'Bad Gateway',
+ new Request('GET', 'test'),
+ new Response(502),
+ ),
+ $this->createAddressResponse([
+ ['fi' => 'Kaivokatu'],
+ ]),
+ new RequestException(
+ 'Forbidden',
+ new Request('GET', 'test'),
+ new Response(403),
+ ),
+ ]);
+
+ $streets = $client->fetchStreetsByPoint(60.171, 24.941);
+
+ $this->assertCount(1, $streets);
+ $this->assertContains('Kaivokatu', $streets);
+
+ // Tests that non-502 errors throw immediately without retrying.
+ $this->expectException(Exception::class);
+ $client->fetchStreetsByPoint(60.171, 24.941);
+ }
+
+}
diff --git a/public/modules/custom/helfi_kymp_content/tests/src/Kernel/PaikkatietoStreetNameDataSourceTest.php b/public/modules/custom/helfi_kymp_content/tests/src/Kernel/PaikkatietoStreetNameDataSourceTest.php
new file mode 100644
index 000000000..1132bb55e
--- /dev/null
+++ b/public/modules/custom/helfi_kymp_content/tests/src/Kernel/PaikkatietoStreetNameDataSourceTest.php
@@ -0,0 +1,119 @@
+ 'Test Index',
+ 'id' => 'test_paikkatieto_street_names',
+ 'status' => FALSE,
+ 'datasource_settings' => [
+ 'paikkatieto_street_name_source' => [],
+ ],
+ 'tracker_settings' => [
+ 'default' => [],
+ ],
+ ]);
+ return $index->getDatasource('paikkatieto_street_name_source');
+ }
+
+ /**
+ * Tests getItemIds returns deduplicated IDs.
+ */
+ public function testGetItemIds(): void {
+ $client = $this->prophesize(PaikkatietoClient::class);
+ $client->fetchStreetNamesByPage(1)
+ ->shouldBeCalled()
+ ->willReturn([
+ ['name' => 'Mannerheimintie', 'language' => 'fi'],
+ ['name' => 'Mannerheimintie', 'language' => 'fi'],
+ ['name' => 'Mannerheimvägen', 'language' => 'sv'],
+ ['name' => 'Kaivokatu', 'language' => 'fi'],
+ ]);
+ $this->container->set(PaikkatietoClient::class, $client->reveal());
+
+ $datasource = $this->getDatasource();
+ $ids = $datasource->getItemIds(0);
+
+ // Duplicates should be removed.
+ $this->assertCount(3, $ids);
+ $this->assertContains('fi:Mannerheimintie', $ids);
+ $this->assertContains('sv:Mannerheimvägen', $ids);
+ $this->assertContains('fi:Kaivokatu', $ids);
+ }
+
+ /**
+ * Tests that getItemIds returns NULL on InvalidArgumentException.
+ */
+ public function testGetItemIdsReturnsNullOnInvalidArgumentException(): void {
+ $client = $this->prophesize(PaikkatietoClient::class);
+ $client->fetchStreetNamesByPage(1)
+ ->shouldBeCalled()
+ ->willThrow(new \InvalidArgumentException('Missing API key'));
+ $this->container->set(PaikkatietoClient::class, $client->reveal());
+
+ $datasource = $this->getDatasource();
+ $this->assertNull($datasource->getItemIds(0));
+ }
+
+ /**
+ * Tests loading a single item from its ID.
+ */
+ public function testLoad(): void {
+ $datasource = $this->getDatasource();
+ $item = $datasource->load('fi:Mannerheimintie');
+
+ $this->assertInstanceOf(ComplexDataInterface::class, $item);
+ $this->assertEquals('fi:Mannerheimintie', $item->get('id')->getString());
+ $this->assertEquals('Mannerheimintie', $item->get('street_name')->getString());
+ $this->assertEquals('fi', $item->get('language')->getString());
+ }
+
+ /**
+ * Tests loading multiple items.
+ */
+ public function testLoadMultiple(): void {
+ $datasource = $this->getDatasource();
+ $items = $datasource->loadMultiple(['fi:Mannerheimintie', 'sv:Mannerheimvägen']);
+
+ $this->assertCount(2, $items);
+ $this->assertArrayHasKey('fi:Mannerheimintie', $items);
+ $this->assertArrayHasKey('sv:Mannerheimvägen', $items);
+ }
+
+}
diff --git a/public/themes/custom/hdbt_subtheme/templates/views/views-view--district-and-project-search.html.twig b/public/themes/custom/hdbt_subtheme/templates/views/views-view--district-and-project-search.html.twig
deleted file mode 100644
index 8d0e5c6f4..000000000
--- a/public/themes/custom/hdbt_subtheme/templates/views/views-view--district-and-project-search.html.twig
+++ /dev/null
@@ -1,16 +0,0 @@
-{#
-/**
- * @file
- * Theme override for main view template.
- */
-#}
-
-{% embed '@hdbt/component/content-list-with-count.twig'%}
- {% block count_container%}
- {%- if total_rows -%}
- {{ total_rows }} {% trans with {'context': 'District and project search fallback'}%}search result{% plural total_rows ?? 0 %}search results{% endtrans %}
- {%- else -%}
- {{ 'No results'|t({}, {'context' : 'Unit search no results title'}) }}
- {%- endif -%}
- {% endblock count_container %}
-{% endembed %}