migration projets: body markdown, images HD, légendes, personnes prénom/nom
- ProjetNode: body Markdown->HTML (strip HTML brut), images + légendes lues
depuis public://drive_shared_leshed/Page{UID}
- ImageResizeImport: nouveau process plugin, redimensionne les images en web HD
(max 1920px) et crée le fichier managé (idempotent)
- field_images: caption via image_field_caption, alt depuis les légendes
- PersonneGenerate: nom dans field_nom (titre auto-généré via auto_entitylabel),
dédup sur field_nom + field_prenom
- title: skip_on_empty (ligne ignorée si "Nom du projet" vide)
- CER: relation curateur sur field_projets_curates (distinct de field_projet_s_lie_s)
- deps: + league/commonmark, image_field_caption, auto_entitylabel ; - migrate_file
This commit is contained in:
@@ -16,15 +16,19 @@
|
|||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"composer/installers": "^2.0",
|
"composer/installers": "^2.0",
|
||||||
|
"drupal/auto_entitylabel": "^3.4",
|
||||||
"drupal/cer": "^5.0@beta",
|
"drupal/cer": "^5.0@beta",
|
||||||
"drupal/config_ignore": "^3.4",
|
"drupal/config_ignore": "^3.4",
|
||||||
"drupal/core-composer-scaffold": "^10.6",
|
"drupal/core-composer-scaffold": "^10.6",
|
||||||
"drupal/core-project-message": "^10.6",
|
"drupal/core-project-message": "^10.6",
|
||||||
"drupal/core-recommended": "^10.6",
|
"drupal/core-recommended": "^10.6",
|
||||||
|
"drupal/image_delta_formatter": "^1.3",
|
||||||
|
"drupal/image_field_caption": "^3.0",
|
||||||
"drupal/migrate_google_sheets": "^2.3",
|
"drupal/migrate_google_sheets": "^2.3",
|
||||||
"drupal/migrate_tools": "^6.1",
|
"drupal/migrate_tools": "^6.1",
|
||||||
"drupal/page_manager": "^4.0@RC",
|
"drupal/page_manager": "^4.0@RC",
|
||||||
"drupal/shield": "^1.8",
|
"drupal/shield": "^1.8",
|
||||||
|
"league/commonmark": "^2.8",
|
||||||
"wikimedia/composer-merge-plugin": "^2.1"
|
"wikimedia/composer-merge-plugin": "^2.1"
|
||||||
},
|
},
|
||||||
"conflict": {
|
"conflict": {
|
||||||
|
|||||||
Generated
+638
-1
@@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "0b0b3210b893eaaa833b27f1e6fae4c9",
|
"content-hash": "5bd9a2694b1628f45febf28ca3f995d7",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "asm89/stack-cors",
|
"name": "asm89/stack-cors",
|
||||||
@@ -1868,6 +1868,87 @@
|
|||||||
"issues": "https://www.drupal.org/project/issues/audiofield"
|
"issues": "https://www.drupal.org/project/issues/audiofield"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "drupal/auto_entitylabel",
|
||||||
|
"version": "3.4.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.drupalcode.org/project/auto_entitylabel.git",
|
||||||
|
"reference": "8.x-3.4"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://ftp.drupal.org/files/projects/auto_entitylabel-8.x-3.4.zip",
|
||||||
|
"reference": "8.x-3.4",
|
||||||
|
"shasum": "9b3d7bc8e450ae008b3f48fed0dd9dace03ddbb5"
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"drupal/core": "^10.1 || ^11"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"drupal/book": "^1.0",
|
||||||
|
"drupal/token": "^1.0"
|
||||||
|
},
|
||||||
|
"type": "drupal-module",
|
||||||
|
"extra": {
|
||||||
|
"drupal": {
|
||||||
|
"version": "8.x-3.4",
|
||||||
|
"datestamp": "1736308389",
|
||||||
|
"security-coverage": {
|
||||||
|
"status": "covered",
|
||||||
|
"message": "Covered by Drupal's security advisory policy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packages.drupal.org/8/downloads",
|
||||||
|
"license": [
|
||||||
|
"GPL-2.0-or-later"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "bforchhammer",
|
||||||
|
"homepage": "https://www.drupal.org/user/216396"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "colan",
|
||||||
|
"homepage": "https://www.drupal.org/user/58704"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dqd",
|
||||||
|
"homepage": "https://www.drupal.org/user/1001934"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "japerry",
|
||||||
|
"homepage": "https://www.drupal.org/user/45640"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mandclu",
|
||||||
|
"homepage": "https://www.drupal.org/user/52136"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "pravin ajaaz",
|
||||||
|
"homepage": "https://www.drupal.org/user/2910049"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "purushotam.rai",
|
||||||
|
"homepage": "https://www.drupal.org/user/3193859"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "renatog",
|
||||||
|
"homepage": "https://www.drupal.org/user/3326031"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vladimiraus",
|
||||||
|
"homepage": "https://www.drupal.org/user/673120"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Allows hiding of entity label fields and automatic label creation.",
|
||||||
|
"homepage": "https://www.drupal.org/project/auto_entitylabel",
|
||||||
|
"support": {
|
||||||
|
"source": "https://git.drupalcode.org/project/auto_entitylabel",
|
||||||
|
"issues": "https://www.drupal.org/project/issues/auto_entitylabel"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "drupal/autocomplete_deluxe",
|
"name": "drupal/autocomplete_deluxe",
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
@@ -4243,6 +4324,131 @@
|
|||||||
"issues": "https://www.drupal.org/project/issues/honeypot"
|
"issues": "https://www.drupal.org/project/issues/honeypot"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "drupal/image_delta_formatter",
|
||||||
|
"version": "1.3.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.drupalcode.org/project/image_delta_formatter.git",
|
||||||
|
"reference": "8.x-1.3"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://ftp.drupal.org/files/projects/image_delta_formatter-8.x-1.3.zip",
|
||||||
|
"reference": "8.x-1.3",
|
||||||
|
"shasum": "6ec48166cb04eda57915dbe28f97fa32c1e77b75"
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"drupal/core": "^10 || ^11"
|
||||||
|
},
|
||||||
|
"type": "drupal-module",
|
||||||
|
"extra": {
|
||||||
|
"drupal": {
|
||||||
|
"version": "8.x-1.3",
|
||||||
|
"datestamp": "1738516937",
|
||||||
|
"security-coverage": {
|
||||||
|
"status": "covered",
|
||||||
|
"message": "Covered by Drupal's security advisory policy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packages.drupal.org/8/downloads",
|
||||||
|
"license": [
|
||||||
|
"GPL-2.0-or-later"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "bojanz",
|
||||||
|
"homepage": "https://www.drupal.org/user/86106"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "fgm",
|
||||||
|
"homepage": "https://www.drupal.org/user/27985"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "jsacksick",
|
||||||
|
"homepage": "https://www.drupal.org/user/972218"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Provides a formatter that displays a specific delta of a multi-value image or media field.",
|
||||||
|
"homepage": "https://www.drupal.org/project/image_delta_formatter",
|
||||||
|
"support": {
|
||||||
|
"source": "https://git.drupalcode.org/project/image_delta_formatter"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "drupal/image_field_caption",
|
||||||
|
"version": "3.0.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.drupalcode.org/project/image_field_caption.git",
|
||||||
|
"reference": "3.0.1"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://ftp.drupal.org/files/projects/image_field_caption-3.0.1.zip",
|
||||||
|
"reference": "3.0.1",
|
||||||
|
"shasum": "e84c3b9534d5824b6a67885187b1c24d4eccaf60"
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"drupal/core": "^10 || ^11"
|
||||||
|
},
|
||||||
|
"type": "drupal-module",
|
||||||
|
"extra": {
|
||||||
|
"drupal": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"datestamp": "1739400507",
|
||||||
|
"security-coverage": {
|
||||||
|
"status": "covered",
|
||||||
|
"message": "Covered by Drupal's security advisory policy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packages.drupal.org/8/downloads",
|
||||||
|
"license": [
|
||||||
|
"GPL-2.0+"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "awm",
|
||||||
|
"homepage": "https://www.drupal.org/user/1059398"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "foxy-vikvik",
|
||||||
|
"homepage": "https://www.drupal.org/user/3706169"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hanoii",
|
||||||
|
"homepage": "https://www.drupal.org/user/23157"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ironsizide",
|
||||||
|
"homepage": "https://www.drupal.org/user/787980"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "istryker",
|
||||||
|
"homepage": "https://www.drupal.org/user/303676"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "kksandr",
|
||||||
|
"homepage": "https://www.drupal.org/user/3710922"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "robloach",
|
||||||
|
"homepage": "https://www.drupal.org/user/61114"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "tyler.frankenstein",
|
||||||
|
"homepage": "https://www.drupal.org/user/150680"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Add caption to image field.",
|
||||||
|
"homepage": "https://www.drupal.org/project/image_field_caption",
|
||||||
|
"support": {
|
||||||
|
"source": "https://git.drupalcode.org/project/image_field_caption",
|
||||||
|
"issues": "https://www.drupal.org/project/issues/image_field_caption"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "drupal/imagemagick",
|
"name": "drupal/imagemagick",
|
||||||
"version": "3.7.0",
|
"version": "3.7.0",
|
||||||
@@ -7864,6 +8070,195 @@
|
|||||||
},
|
},
|
||||||
"time": "2026-06-26T00:11:25+00:00"
|
"time": "2026-06-26T00:11:25+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "league/commonmark",
|
||||||
|
"version": "2.8.3",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/thephpleague/commonmark.git",
|
||||||
|
"reference": "1902f60f984235023acbe03db6ad614a37b3c3e7"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/1902f60f984235023acbe03db6ad614a37b3c3e7",
|
||||||
|
"reference": "1902f60f984235023acbe03db6ad614a37b3c3e7",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"league/config": "^1.1.1",
|
||||||
|
"php": "^7.4 || ^8.0",
|
||||||
|
"psr/event-dispatcher": "^1.0",
|
||||||
|
"symfony/deprecation-contracts": "^2.1 || ^3.0",
|
||||||
|
"symfony/polyfill-php80": "^1.16"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"cebe/markdown": "^1.0",
|
||||||
|
"commonmark/cmark": "0.31.1",
|
||||||
|
"commonmark/commonmark.js": "0.31.1",
|
||||||
|
"composer/package-versions-deprecated": "^1.8",
|
||||||
|
"embed/embed": "^4.4",
|
||||||
|
"erusev/parsedown": "^1.0",
|
||||||
|
"ext-json": "*",
|
||||||
|
"github/gfm": "0.29.0",
|
||||||
|
"michelf/php-markdown": "^1.4 || ^2.0",
|
||||||
|
"nyholm/psr7": "^1.5",
|
||||||
|
"phpstan/phpstan": "^2.0.0",
|
||||||
|
"phpunit/phpunit": "^9.5.21 || ^10.5.9 || ^11.0.0 || ^12.0.0 || ^13.0.0",
|
||||||
|
"scrutinizer/ocular": "^1.8.1",
|
||||||
|
"symfony/finder": "^5.3 | ^6.0 | ^7.0 || ^8.0",
|
||||||
|
"symfony/process": "^5.4 | ^6.0 | ^7.0 || ^8.0",
|
||||||
|
"symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0 || ^8.0",
|
||||||
|
"unleashedtech/php-coding-standard": "^3.1.1",
|
||||||
|
"vimeo/psalm": "^4.24.0 || ^5.0.0 || ^6.0.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"symfony/yaml": "v2.3+ required if using the Front Matter extension"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "2.9-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"League\\CommonMark\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Colin O'Dell",
|
||||||
|
"email": "colinodell@gmail.com",
|
||||||
|
"homepage": "https://www.colinodell.com",
|
||||||
|
"role": "Lead Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and GitHub-Flavored Markdown (GFM)",
|
||||||
|
"homepage": "https://commonmark.thephpleague.com",
|
||||||
|
"keywords": [
|
||||||
|
"commonmark",
|
||||||
|
"flavored",
|
||||||
|
"gfm",
|
||||||
|
"github",
|
||||||
|
"github-flavored",
|
||||||
|
"markdown",
|
||||||
|
"md",
|
||||||
|
"parser"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"docs": "https://commonmark.thephpleague.com/",
|
||||||
|
"forum": "https://github.com/thephpleague/commonmark/discussions",
|
||||||
|
"issues": "https://github.com/thephpleague/commonmark/issues",
|
||||||
|
"rss": "https://github.com/thephpleague/commonmark/releases.atom",
|
||||||
|
"source": "https://github.com/thephpleague/commonmark"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://www.colinodell.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://www.paypal.me/colinpodell/10.00",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/colinodell",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/league/commonmark",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2026-07-12T15:29:16+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "league/config",
|
||||||
|
"version": "v1.2.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/thephpleague/config.git",
|
||||||
|
"reference": "754b3604fb2984c71f4af4a9cbe7b57f346ec1f3"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/thephpleague/config/zipball/754b3604fb2984c71f4af4a9cbe7b57f346ec1f3",
|
||||||
|
"reference": "754b3604fb2984c71f4af4a9cbe7b57f346ec1f3",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"dflydev/dot-access-data": "^3.0.1",
|
||||||
|
"nette/schema": "^1.2",
|
||||||
|
"php": "^7.4 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpstan/phpstan": "^1.8.2",
|
||||||
|
"phpunit/phpunit": "^9.5.5",
|
||||||
|
"scrutinizer/ocular": "^1.8.1",
|
||||||
|
"unleashedtech/php-coding-standard": "^3.1",
|
||||||
|
"vimeo/psalm": "^4.7.3"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "1.2-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"League\\Config\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Colin O'Dell",
|
||||||
|
"email": "colinodell@gmail.com",
|
||||||
|
"homepage": "https://www.colinodell.com",
|
||||||
|
"role": "Lead Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Define configuration arrays with strict schemas and access values with dot notation",
|
||||||
|
"homepage": "https://config.thephpleague.com",
|
||||||
|
"keywords": [
|
||||||
|
"array",
|
||||||
|
"config",
|
||||||
|
"configuration",
|
||||||
|
"dot",
|
||||||
|
"dot-access",
|
||||||
|
"nested",
|
||||||
|
"schema"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"docs": "https://config.thephpleague.com/",
|
||||||
|
"issues": "https://github.com/thephpleague/config/issues",
|
||||||
|
"rss": "https://github.com/thephpleague/config/releases.atom",
|
||||||
|
"source": "https://github.com/thephpleague/config"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://www.colinodell.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://www.paypal.me/colinpodell/10.00",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/colinodell",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2022-12-11T20:36:23+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "league/container",
|
"name": "league/container",
|
||||||
"version": "4.2.5",
|
"version": "4.2.5",
|
||||||
@@ -8062,6 +8457,164 @@
|
|||||||
},
|
},
|
||||||
"time": "2026-04-24T08:04:05+00:00"
|
"time": "2026-04-24T08:04:05+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "nette/schema",
|
||||||
|
"version": "v1.3.5",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/nette/schema.git",
|
||||||
|
"reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/nette/schema/zipball/f0ab1a3cda782dbc5da270d28545236aa80c4002",
|
||||||
|
"reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"nette/utils": "^4.0",
|
||||||
|
"php": "8.1 - 8.5"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"nette/phpstan-rules": "^1.0",
|
||||||
|
"nette/tester": "^2.6",
|
||||||
|
"phpstan/extension-installer": "^1.4@stable",
|
||||||
|
"phpstan/phpstan": "^2.1.39@stable",
|
||||||
|
"tracy/tracy": "^2.8"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.3-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Nette\\": "src"
|
||||||
|
},
|
||||||
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"BSD-3-Clause",
|
||||||
|
"GPL-2.0-only",
|
||||||
|
"GPL-3.0-only"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "David Grudl",
|
||||||
|
"homepage": "https://davidgrudl.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Nette Community",
|
||||||
|
"homepage": "https://nette.org/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "📐 Nette Schema: validating data structures against a given Schema.",
|
||||||
|
"homepage": "https://nette.org",
|
||||||
|
"keywords": [
|
||||||
|
"config",
|
||||||
|
"nette"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/nette/schema/issues",
|
||||||
|
"source": "https://github.com/nette/schema/tree/v1.3.5"
|
||||||
|
},
|
||||||
|
"time": "2026-02-23T03:47:12+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "nette/utils",
|
||||||
|
"version": "v4.1.5",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/nette/utils.git",
|
||||||
|
"reference": "b043439dbdf954e6c28b5ea7e34b0100f83165e0"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/nette/utils/zipball/b043439dbdf954e6c28b5ea7e34b0100f83165e0",
|
||||||
|
"reference": "b043439dbdf954e6c28b5ea7e34b0100f83165e0",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "8.2 - 8.5"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"nette/finder": "<3",
|
||||||
|
"nette/schema": "<1.2.2"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"jetbrains/phpstorm-attributes": "^1.2",
|
||||||
|
"nette/phpstan-rules": "^1.0",
|
||||||
|
"nette/tester": "^2.5",
|
||||||
|
"phpstan/extension-installer": "^1.4@stable",
|
||||||
|
"phpstan/phpstan": "^2.1@stable",
|
||||||
|
"tracy/tracy": "^2.9"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-gd": "to use Image",
|
||||||
|
"ext-iconv": "to use Strings::chr(), ord() and reverse()",
|
||||||
|
"ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()",
|
||||||
|
"ext-json": "to use Nette\\Utils\\Json",
|
||||||
|
"ext-mbstring": "to use Strings::lower() etc...",
|
||||||
|
"ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "4.1-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Nette\\": "src"
|
||||||
|
},
|
||||||
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"BSD-3-Clause",
|
||||||
|
"GPL-2.0-only",
|
||||||
|
"GPL-3.0-only"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "David Grudl",
|
||||||
|
"homepage": "https://davidgrudl.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Nette Community",
|
||||||
|
"homepage": "https://nette.org/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.",
|
||||||
|
"homepage": "https://nette.org",
|
||||||
|
"keywords": [
|
||||||
|
"array",
|
||||||
|
"core",
|
||||||
|
"datetime",
|
||||||
|
"images",
|
||||||
|
"json",
|
||||||
|
"nette",
|
||||||
|
"paginator",
|
||||||
|
"password",
|
||||||
|
"slugify",
|
||||||
|
"string",
|
||||||
|
"unicode",
|
||||||
|
"utf-8",
|
||||||
|
"utility",
|
||||||
|
"validation"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/nette/utils/issues",
|
||||||
|
"source": "https://github.com/nette/utils/tree/v4.1.5"
|
||||||
|
},
|
||||||
|
"time": "2026-07-17T23:02:45+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "nikic/php-parser",
|
"name": "nikic/php-parser",
|
||||||
"version": "v5.8.0",
|
"version": "v5.8.0",
|
||||||
@@ -10687,6 +11240,90 @@
|
|||||||
],
|
],
|
||||||
"time": "2026-04-10T17:25:58+00:00"
|
"time": "2026-04-10T17:25:58+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/polyfill-php80",
|
||||||
|
"version": "v1.37.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/polyfill-php80.git",
|
||||||
|
"reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dfb55726c3a76ea3b6459fcfda1ec2d80a682411",
|
||||||
|
"reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.2"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"thanks": {
|
||||||
|
"url": "https://github.com/symfony/polyfill",
|
||||||
|
"name": "symfony/polyfill"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"bootstrap.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Polyfill\\Php80\\": ""
|
||||||
|
},
|
||||||
|
"classmap": [
|
||||||
|
"Resources/stubs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Ion Bazan",
|
||||||
|
"email": "ion.bazan@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "p@tchwork.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"compatibility",
|
||||||
|
"polyfill",
|
||||||
|
"portable",
|
||||||
|
"shim"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/polyfill-php80/tree/v1.37.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/nicolas-grekas",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2026-04-10T16:19:22+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/polyfill-php81",
|
"name": "symfony/polyfill-php81",
|
||||||
"version": "v1.38.1",
|
"version": "v1.38.1",
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
status: 1
|
||||||
|
pattern: '[node:field_prenom] [node:field_nom]'
|
||||||
|
escape: false
|
||||||
|
preserve_titles: false
|
||||||
|
save: true
|
||||||
|
chunk: 50
|
||||||
|
dependencies:
|
||||||
|
config:
|
||||||
|
- node.type.personne
|
||||||
|
new_content_behavior: 0
|
||||||
@@ -6,7 +6,7 @@ id: projet_curateur
|
|||||||
label: 'Projet - Curateur'
|
label: 'Projet - Curateur'
|
||||||
enabled: true
|
enabled: true
|
||||||
first_field: field_invite_accompagne_curate_p
|
first_field: field_invite_accompagne_curate_p
|
||||||
second_field: field_projet_s_lie_s
|
second_field: field_projets_curates
|
||||||
add_direction: append
|
add_direction: append
|
||||||
bundles:
|
bundles:
|
||||||
node:
|
node:
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ id: node.personne.title
|
|||||||
field_name: title
|
field_name: title
|
||||||
entity_type: node
|
entity_type: node
|
||||||
bundle: personne
|
bundle: personne
|
||||||
label: Nom
|
label: Title
|
||||||
description: ''
|
description: ''
|
||||||
required: true
|
required: true
|
||||||
translatable: true
|
translatable: true
|
||||||
|
|||||||
@@ -162,4 +162,9 @@ content:
|
|||||||
size: 60
|
size: 60
|
||||||
placeholder: ''
|
placeholder: ''
|
||||||
third_party_settings: { }
|
third_party_settings: { }
|
||||||
|
url_redirects:
|
||||||
|
weight: 50
|
||||||
|
region: content
|
||||||
|
settings: { }
|
||||||
|
third_party_settings: { }
|
||||||
hidden: { }
|
hidden: { }
|
||||||
|
|||||||
@@ -89,4 +89,9 @@ content:
|
|||||||
size: 60
|
size: 60
|
||||||
placeholder: ''
|
placeholder: ''
|
||||||
third_party_settings: { }
|
third_party_settings: { }
|
||||||
|
url_redirects:
|
||||||
|
weight: 50
|
||||||
|
region: content
|
||||||
|
settings: { }
|
||||||
|
third_party_settings: { }
|
||||||
hidden: { }
|
hidden: { }
|
||||||
|
|||||||
@@ -4,8 +4,10 @@ status: true
|
|||||||
dependencies:
|
dependencies:
|
||||||
config:
|
config:
|
||||||
- field.field.node.personne.body
|
- field.field.node.personne.body
|
||||||
|
- field.field.node.personne.field_nom
|
||||||
- field.field.node.personne.field_prenom
|
- field.field.node.personne.field_prenom
|
||||||
- field.field.node.personne.field_projet_s_lie_s
|
- field.field.node.personne.field_projet_s_lie_s
|
||||||
|
- field.field.node.personne.field_projets_curates
|
||||||
- field.field.node.personne.field_type_de_personne
|
- field.field.node.personne.field_type_de_personne
|
||||||
- node.type.personne
|
- node.type.personne
|
||||||
module:
|
module:
|
||||||
@@ -23,7 +25,7 @@ third_party_settings:
|
|||||||
label: Details
|
label: Details
|
||||||
region: content
|
region: content
|
||||||
parent_name: ''
|
parent_name: ''
|
||||||
weight: 4
|
weight: 5
|
||||||
format_type: details_sidebar
|
format_type: details_sidebar
|
||||||
format_settings:
|
format_settings:
|
||||||
classes: ''
|
classes: ''
|
||||||
@@ -41,7 +43,7 @@ mode: default
|
|||||||
content:
|
content:
|
||||||
body:
|
body:
|
||||||
type: text_textarea_with_summary
|
type: text_textarea_with_summary
|
||||||
weight: 2
|
weight: 3
|
||||||
region: content
|
region: content
|
||||||
settings:
|
settings:
|
||||||
rows: 9
|
rows: 9
|
||||||
@@ -49,6 +51,14 @@ content:
|
|||||||
placeholder: ''
|
placeholder: ''
|
||||||
show_summary: false
|
show_summary: false
|
||||||
third_party_settings: { }
|
third_party_settings: { }
|
||||||
|
field_nom:
|
||||||
|
type: string_textfield
|
||||||
|
weight: 2
|
||||||
|
region: content
|
||||||
|
settings:
|
||||||
|
size: 60
|
||||||
|
placeholder: ''
|
||||||
|
third_party_settings: { }
|
||||||
field_prenom:
|
field_prenom:
|
||||||
type: string_textfield
|
type: string_textfield
|
||||||
weight: 1
|
weight: 1
|
||||||
@@ -59,7 +69,17 @@ content:
|
|||||||
third_party_settings: { }
|
third_party_settings: { }
|
||||||
field_projet_s_lie_s:
|
field_projet_s_lie_s:
|
||||||
type: entity_reference_autocomplete
|
type: entity_reference_autocomplete
|
||||||
weight: 3
|
weight: 4
|
||||||
|
region: content
|
||||||
|
settings:
|
||||||
|
match_operator: CONTAINS
|
||||||
|
match_limit: 10
|
||||||
|
size: 60
|
||||||
|
placeholder: ''
|
||||||
|
third_party_settings: { }
|
||||||
|
field_projets_curates:
|
||||||
|
type: entity_reference_autocomplete
|
||||||
|
weight: 26
|
||||||
region: content
|
region: content
|
||||||
settings:
|
settings:
|
||||||
match_operator: CONTAINS
|
match_operator: CONTAINS
|
||||||
|
|||||||
@@ -257,6 +257,11 @@ content:
|
|||||||
size: 60
|
size: 60
|
||||||
placeholder: ''
|
placeholder: ''
|
||||||
third_party_settings: { }
|
third_party_settings: { }
|
||||||
|
url_redirects:
|
||||||
|
weight: 50
|
||||||
|
region: content
|
||||||
|
settings: { }
|
||||||
|
third_party_settings: { }
|
||||||
hidden:
|
hidden:
|
||||||
created: true
|
created: true
|
||||||
sticky: true
|
sticky: true
|
||||||
|
|||||||
@@ -4,8 +4,10 @@ status: true
|
|||||||
dependencies:
|
dependencies:
|
||||||
config:
|
config:
|
||||||
- field.field.node.personne.body
|
- field.field.node.personne.body
|
||||||
|
- field.field.node.personne.field_nom
|
||||||
- field.field.node.personne.field_prenom
|
- field.field.node.personne.field_prenom
|
||||||
- field.field.node.personne.field_projet_s_lie_s
|
- field.field.node.personne.field_projet_s_lie_s
|
||||||
|
- field.field.node.personne.field_projets_curates
|
||||||
- field.field.node.personne.field_type_de_personne
|
- field.field.node.personne.field_type_de_personne
|
||||||
- node.type.personne
|
- node.type.personne
|
||||||
module:
|
module:
|
||||||
@@ -23,6 +25,14 @@ content:
|
|||||||
third_party_settings: { }
|
third_party_settings: { }
|
||||||
weight: 101
|
weight: 101
|
||||||
region: content
|
region: content
|
||||||
|
field_nom:
|
||||||
|
type: string
|
||||||
|
label: above
|
||||||
|
settings:
|
||||||
|
link_to_entity: false
|
||||||
|
third_party_settings: { }
|
||||||
|
weight: 109
|
||||||
|
region: content
|
||||||
field_prenom:
|
field_prenom:
|
||||||
type: string
|
type: string
|
||||||
label: above
|
label: above
|
||||||
@@ -39,6 +49,14 @@ content:
|
|||||||
third_party_settings: { }
|
third_party_settings: { }
|
||||||
weight: 108
|
weight: 108
|
||||||
region: content
|
region: content
|
||||||
|
field_projets_curates:
|
||||||
|
type: entity_reference_label
|
||||||
|
label: above
|
||||||
|
settings:
|
||||||
|
link: true
|
||||||
|
third_party_settings: { }
|
||||||
|
weight: 110
|
||||||
|
region: content
|
||||||
field_type_de_personne:
|
field_type_de_personne:
|
||||||
type: entity_reference_label
|
type: entity_reference_label
|
||||||
label: above
|
label: above
|
||||||
|
|||||||
@@ -5,34 +5,26 @@ dependencies:
|
|||||||
config:
|
config:
|
||||||
- core.entity_view_mode.node.teaser
|
- core.entity_view_mode.node.teaser
|
||||||
- field.field.node.personne.body
|
- field.field.node.personne.body
|
||||||
|
- field.field.node.personne.field_nom
|
||||||
- field.field.node.personne.field_prenom
|
- field.field.node.personne.field_prenom
|
||||||
- field.field.node.personne.field_projet_s_lie_s
|
- field.field.node.personne.field_projet_s_lie_s
|
||||||
|
- field.field.node.personne.field_projets_curates
|
||||||
- field.field.node.personne.field_type_de_personne
|
- field.field.node.personne.field_type_de_personne
|
||||||
- node.type.personne
|
- node.type.personne
|
||||||
module:
|
module:
|
||||||
- text
|
|
||||||
- user
|
- user
|
||||||
id: node.personne.teaser
|
id: node.personne.teaser
|
||||||
targetEntityType: node
|
targetEntityType: node
|
||||||
bundle: personne
|
bundle: personne
|
||||||
mode: teaser
|
mode: teaser
|
||||||
content:
|
content: { }
|
||||||
body:
|
|
||||||
type: text_summary_or_trimmed
|
|
||||||
label: hidden
|
|
||||||
settings:
|
|
||||||
trim_length: 600
|
|
||||||
third_party_settings: { }
|
|
||||||
weight: 101
|
|
||||||
region: content
|
|
||||||
links:
|
|
||||||
settings: { }
|
|
||||||
third_party_settings: { }
|
|
||||||
weight: 100
|
|
||||||
region: content
|
|
||||||
hidden:
|
hidden:
|
||||||
|
body: true
|
||||||
|
field_nom: true
|
||||||
field_prenom: true
|
field_prenom: true
|
||||||
field_projet_s_lie_s: true
|
field_projet_s_lie_s: true
|
||||||
|
field_projets_curates: true
|
||||||
field_type_de_personne: true
|
field_type_de_personne: true
|
||||||
langcode: true
|
langcode: true
|
||||||
|
links: true
|
||||||
search_api_excerpt: true
|
search_api_excerpt: true
|
||||||
|
|||||||
@@ -13,8 +13,10 @@ dependencies:
|
|||||||
- field.field.node.projet.field_portage
|
- field.field.node.projet.field_portage
|
||||||
- field.field.node.projet.field_projet_s_lie_s
|
- field.field.node.projet.field_projet_s_lie_s
|
||||||
- field.field.node.projet.field_type_de_projet
|
- field.field.node.projet.field_type_de_projet
|
||||||
|
- image.style.medium
|
||||||
- node.type.projet
|
- node.type.projet
|
||||||
module:
|
module:
|
||||||
|
- image_delta_formatter
|
||||||
- text
|
- text
|
||||||
- user
|
- user
|
||||||
id: node.projet.teaser
|
id: node.projet.teaser
|
||||||
@@ -26,23 +28,40 @@ content:
|
|||||||
type: text_summary_or_trimmed
|
type: text_summary_or_trimmed
|
||||||
label: hidden
|
label: hidden
|
||||||
settings:
|
settings:
|
||||||
trim_length: 600
|
trim_length: 100
|
||||||
third_party_settings: { }
|
third_party_settings: { }
|
||||||
weight: 101
|
weight: 2
|
||||||
region: content
|
region: content
|
||||||
links:
|
field_artiste_s_invite_s:
|
||||||
settings: { }
|
type: entity_reference_entity_view
|
||||||
|
label: hidden
|
||||||
|
settings:
|
||||||
|
view_mode: teaser
|
||||||
|
link: false
|
||||||
third_party_settings: { }
|
third_party_settings: { }
|
||||||
weight: 100
|
weight: 1
|
||||||
|
region: content
|
||||||
|
field_images:
|
||||||
|
type: image_delta_formatter
|
||||||
|
label: hidden
|
||||||
|
settings:
|
||||||
|
deltas:
|
||||||
|
- 1
|
||||||
|
deltas_reversed: false
|
||||||
|
image_link: content
|
||||||
|
image_style: medium
|
||||||
|
image_loading:
|
||||||
|
attribute: lazy
|
||||||
|
third_party_settings: { }
|
||||||
|
weight: 0
|
||||||
region: content
|
region: content
|
||||||
hidden:
|
hidden:
|
||||||
field_artiste_s_invite_s: true
|
|
||||||
field_dates: true
|
field_dates: true
|
||||||
field_images: true
|
|
||||||
field_invite_accompagne_curate_p: true
|
field_invite_accompagne_curate_p: true
|
||||||
field_partenaire_s: true
|
field_partenaire_s: true
|
||||||
field_portage: true
|
field_portage: true
|
||||||
field_projet_s_lie_s: true
|
field_projet_s_lie_s: true
|
||||||
field_type_de_projet: true
|
field_type_de_projet: true
|
||||||
langcode: true
|
langcode: true
|
||||||
|
links: true
|
||||||
search_api_excerpt: true
|
search_api_excerpt: true
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
_core:
|
_core:
|
||||||
default_config_hash: 4GIX5Esnc_umpXUBj4IIocRX7Mt5fPhm4AgXfE3E56E
|
default_config_hash: 4GIX5Esnc_umpXUBj4IIocRX7Mt5fPhm4AgXfE3E56E
|
||||||
module:
|
module:
|
||||||
|
auto_entitylabel: -100
|
||||||
actions_permissions: 0
|
actions_permissions: 0
|
||||||
address: 0
|
address: 0
|
||||||
admin_toolbar: 0
|
admin_toolbar: 0
|
||||||
@@ -52,6 +53,8 @@ module:
|
|||||||
help: 0
|
help: 0
|
||||||
honeypot: 0
|
honeypot: 0
|
||||||
image: 0
|
image: 0
|
||||||
|
image_delta_formatter: 0
|
||||||
|
image_field_caption: 0
|
||||||
inline_entity_form: 0
|
inline_entity_form: 0
|
||||||
language: 0
|
language: 0
|
||||||
layout_builder: 0
|
layout_builder: 0
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
uuid: 7f1a16d3-57ea-4861-ad4f-1312ceadd1e7
|
||||||
|
langcode: fr
|
||||||
|
status: true
|
||||||
|
dependencies:
|
||||||
|
config:
|
||||||
|
- field.storage.node.field_nom
|
||||||
|
- node.type.personne
|
||||||
|
id: node.personne.field_nom
|
||||||
|
field_name: field_nom
|
||||||
|
entity_type: node
|
||||||
|
bundle: personne
|
||||||
|
label: Nom
|
||||||
|
description: ''
|
||||||
|
required: true
|
||||||
|
translatable: false
|
||||||
|
default_value: { }
|
||||||
|
default_value_callback: ''
|
||||||
|
settings: { }
|
||||||
|
field_type: string
|
||||||
@@ -11,7 +11,7 @@ entity_type: node
|
|||||||
bundle: personne
|
bundle: personne
|
||||||
label: Prenom
|
label: Prenom
|
||||||
description: ''
|
description: ''
|
||||||
required: false
|
required: true
|
||||||
translatable: false
|
translatable: false
|
||||||
default_value: { }
|
default_value: { }
|
||||||
default_value_callback: ''
|
default_value_callback: ''
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
uuid: 75b15206-7946-48cb-b7b9-17c27ad00c25
|
||||||
|
langcode: fr
|
||||||
|
status: true
|
||||||
|
dependencies:
|
||||||
|
config:
|
||||||
|
- field.storage.node.field_projets_curates
|
||||||
|
- node.type.personne
|
||||||
|
- node.type.projet
|
||||||
|
id: node.personne.field_projets_curates
|
||||||
|
field_name: field_projets_curates
|
||||||
|
entity_type: node
|
||||||
|
bundle: personne
|
||||||
|
label: projets_curates
|
||||||
|
description: ''
|
||||||
|
required: false
|
||||||
|
translatable: false
|
||||||
|
default_value: { }
|
||||||
|
default_value_callback: ''
|
||||||
|
settings:
|
||||||
|
handler: 'default:node'
|
||||||
|
handler_settings:
|
||||||
|
target_bundles:
|
||||||
|
projet: projet
|
||||||
|
sort:
|
||||||
|
field: _none
|
||||||
|
direction: ASC
|
||||||
|
auto_create: false
|
||||||
|
auto_create_bundle: ''
|
||||||
|
field_type: entity_reference
|
||||||
@@ -35,4 +35,7 @@ settings:
|
|||||||
title: ''
|
title: ''
|
||||||
width: null
|
width: null
|
||||||
height: null
|
height: null
|
||||||
|
caption: ''
|
||||||
|
caption_field: 1
|
||||||
|
caption_field_required: 0
|
||||||
field_type: image
|
field_type: image
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
uuid: 14aa5aef-0840-4e3d-a78a-027e2c61844f
|
||||||
|
langcode: fr
|
||||||
|
status: true
|
||||||
|
dependencies:
|
||||||
|
module:
|
||||||
|
- node
|
||||||
|
id: node.field_nom
|
||||||
|
field_name: field_nom
|
||||||
|
entity_type: node
|
||||||
|
type: string
|
||||||
|
settings:
|
||||||
|
max_length: 255
|
||||||
|
case_sensitive: false
|
||||||
|
is_ascii: false
|
||||||
|
module: core
|
||||||
|
locked: false
|
||||||
|
cardinality: 1
|
||||||
|
translatable: true
|
||||||
|
indexes: { }
|
||||||
|
persist_with_no_fields: false
|
||||||
|
custom_storage: false
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
uuid: c5d97546-10d2-46e0-9324-1164bdd04cbb
|
||||||
|
langcode: fr
|
||||||
|
status: true
|
||||||
|
dependencies:
|
||||||
|
module:
|
||||||
|
- node
|
||||||
|
id: node.field_projets_curates
|
||||||
|
field_name: field_projets_curates
|
||||||
|
entity_type: node
|
||||||
|
type: entity_reference
|
||||||
|
settings:
|
||||||
|
target_type: node
|
||||||
|
module: core
|
||||||
|
locked: false
|
||||||
|
cardinality: -1
|
||||||
|
translatable: true
|
||||||
|
indexes: { }
|
||||||
|
persist_with_no_fields: false
|
||||||
|
custom_storage: false
|
||||||
@@ -15,6 +15,8 @@ source:
|
|||||||
plugin: projet_node
|
plugin: projet_node
|
||||||
data_fetcher_plugin: http
|
data_fetcher_plugin: http
|
||||||
data_parser_plugin: google_sheets
|
data_parser_plugin: google_sheets
|
||||||
|
constants:
|
||||||
|
images_destination: 'public://projets/'
|
||||||
urls: 'https://sheets.googleapis.com/v4/spreadsheets/1561Gv1C-IlCTmg64Z8HnznvOeLbvwhA_k1l6aq95zFA/values/Projets'
|
urls: 'https://sheets.googleapis.com/v4/spreadsheets/1561Gv1C-IlCTmg64Z8HnznvOeLbvwhA_k1l6aq95zFA/values/Projets'
|
||||||
fields:
|
fields:
|
||||||
-
|
-
|
||||||
@@ -56,7 +58,32 @@ process:
|
|||||||
type:
|
type:
|
||||||
plugin: default_value
|
plugin: default_value
|
||||||
default_value: projet
|
default_value: projet
|
||||||
title: title
|
title:
|
||||||
|
plugin: skip_on_empty
|
||||||
|
method: row
|
||||||
|
source: title
|
||||||
|
message: 'Projet ignoré : « Nom du projet » vide.'
|
||||||
|
body/value: body_html
|
||||||
|
body/format:
|
||||||
|
plugin: default_value
|
||||||
|
default_value: wysiwyg
|
||||||
|
field_images:
|
||||||
|
plugin: sub_process
|
||||||
|
source: images
|
||||||
|
process:
|
||||||
|
target_id:
|
||||||
|
plugin: image_resize_import
|
||||||
|
source: uri
|
||||||
|
destination: destination
|
||||||
|
max_width: 1920
|
||||||
|
max_height: 1920
|
||||||
|
reuse: true
|
||||||
|
skip_on_missing_source: true
|
||||||
|
alt: alt
|
||||||
|
image_field_caption/value: caption
|
||||||
|
image_field_caption/format:
|
||||||
|
plugin: default_value
|
||||||
|
default_value: wysiwyg
|
||||||
field_dates/value:
|
field_dates/value:
|
||||||
plugin: leshed_date
|
plugin: leshed_date
|
||||||
source: date_start
|
source: date_start
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
langcode: fr
|
||||||
_core:
|
_core:
|
||||||
default_config_hash: R7HmKRbuDsDQNpqEWt7wWcf0ygaE3u-NQQr-w_LhHJk
|
default_config_hash: R7HmKRbuDsDQNpqEWt7wWcf0ygaE3u-NQQr-w_LhHJk
|
||||||
auto_redirect: true
|
auto_redirect: true
|
||||||
@@ -7,4 +8,3 @@ warning: false
|
|||||||
ignore_admin_path: false
|
ignore_admin_path: false
|
||||||
access_check: false
|
access_check: false
|
||||||
route_normalizer_enabled: true
|
route_normalizer_enabled: true
|
||||||
langcode: fr
|
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ langcode: fr
|
|||||||
status: true
|
status: true
|
||||||
dependencies:
|
dependencies:
|
||||||
config:
|
config:
|
||||||
- field.storage.node.field_prenom
|
- field.storage.node.field_projet_s_lie_s
|
||||||
|
- field.storage.node.field_projets_curates
|
||||||
- field.storage.node.field_type_de_projet
|
- field.storage.node.field_type_de_projet
|
||||||
module:
|
module:
|
||||||
- node
|
- node
|
||||||
@@ -107,69 +108,6 @@ display:
|
|||||||
multi_type: separator
|
multi_type: separator
|
||||||
separator: ', '
|
separator: ', '
|
||||||
field_api_classes: false
|
field_api_classes: false
|
||||||
field_prenom:
|
|
||||||
id: field_prenom
|
|
||||||
table: node__field_prenom
|
|
||||||
field: field_prenom
|
|
||||||
relationship: none
|
|
||||||
group_type: group
|
|
||||||
admin_label: ''
|
|
||||||
plugin_id: field
|
|
||||||
label: ''
|
|
||||||
exclude: true
|
|
||||||
alter:
|
|
||||||
alter_text: false
|
|
||||||
text: ''
|
|
||||||
make_link: false
|
|
||||||
path: ''
|
|
||||||
absolute: false
|
|
||||||
external: false
|
|
||||||
replace_spaces: false
|
|
||||||
path_case: none
|
|
||||||
trim_whitespace: false
|
|
||||||
alt: ''
|
|
||||||
rel: ''
|
|
||||||
link_class: ''
|
|
||||||
prefix: ''
|
|
||||||
suffix: ''
|
|
||||||
target: ''
|
|
||||||
nl2br: false
|
|
||||||
max_length: 0
|
|
||||||
word_boundary: true
|
|
||||||
ellipsis: true
|
|
||||||
more_link: false
|
|
||||||
more_link_text: ''
|
|
||||||
more_link_path: ''
|
|
||||||
strip_tags: false
|
|
||||||
trim: false
|
|
||||||
preserve_tags: ''
|
|
||||||
html: false
|
|
||||||
element_type: ''
|
|
||||||
element_class: ''
|
|
||||||
element_label_type: ''
|
|
||||||
element_label_class: ''
|
|
||||||
element_label_colon: false
|
|
||||||
element_wrapper_type: ''
|
|
||||||
element_wrapper_class: ''
|
|
||||||
element_default_classes: true
|
|
||||||
empty: ''
|
|
||||||
hide_empty: false
|
|
||||||
empty_zero: false
|
|
||||||
hide_alter_empty: true
|
|
||||||
click_sort_column: value
|
|
||||||
type: string
|
|
||||||
settings:
|
|
||||||
link_to_entity: true
|
|
||||||
group_column: value
|
|
||||||
group_columns: { }
|
|
||||||
group_rows: true
|
|
||||||
delta_limit: 0
|
|
||||||
delta_offset: 0
|
|
||||||
delta_reversed: false
|
|
||||||
delta_first_last: false
|
|
||||||
multi_type: separator
|
|
||||||
separator: ', '
|
|
||||||
field_api_classes: false
|
|
||||||
title:
|
title:
|
||||||
id: title
|
id: title
|
||||||
table: node_field_data
|
table: node_field_data
|
||||||
@@ -183,7 +121,7 @@ display:
|
|||||||
label: Titre
|
label: Titre
|
||||||
exclude: false
|
exclude: false
|
||||||
alter:
|
alter:
|
||||||
alter_text: true
|
alter_text: false
|
||||||
text: '{{ field_prenom }} {{ title }}'
|
text: '{{ field_prenom }} {{ title }}'
|
||||||
make_link: false
|
make_link: false
|
||||||
path: ''
|
path: ''
|
||||||
@@ -298,25 +236,132 @@ display:
|
|||||||
multi_type: separator
|
multi_type: separator
|
||||||
separator: ', '
|
separator: ', '
|
||||||
field_api_classes: false
|
field_api_classes: false
|
||||||
name:
|
field_projet_s_lie_s:
|
||||||
id: name
|
id: field_projet_s_lie_s
|
||||||
table: users_field_data
|
table: node__field_projet_s_lie_s
|
||||||
field: name
|
field: field_projet_s_lie_s
|
||||||
relationship: uid
|
relationship: none
|
||||||
entity_type: user
|
group_type: group
|
||||||
entity_field: name
|
admin_label: ''
|
||||||
plugin_id: field
|
plugin_id: field
|
||||||
label: Auteur
|
label: 'Projet(s) lié(s)'
|
||||||
exclude: false
|
exclude: false
|
||||||
alter:
|
alter:
|
||||||
alter_text: false
|
alter_text: false
|
||||||
|
text: ''
|
||||||
|
make_link: false
|
||||||
|
path: ''
|
||||||
|
absolute: false
|
||||||
|
external: false
|
||||||
|
replace_spaces: false
|
||||||
|
path_case: none
|
||||||
|
trim_whitespace: false
|
||||||
|
alt: ''
|
||||||
|
rel: ''
|
||||||
|
link_class: ''
|
||||||
|
prefix: ''
|
||||||
|
suffix: ''
|
||||||
|
target: ''
|
||||||
|
nl2br: false
|
||||||
|
max_length: 0
|
||||||
|
word_boundary: true
|
||||||
|
ellipsis: true
|
||||||
|
more_link: false
|
||||||
|
more_link_text: ''
|
||||||
|
more_link_path: ''
|
||||||
|
strip_tags: false
|
||||||
|
trim: false
|
||||||
|
preserve_tags: ''
|
||||||
|
html: false
|
||||||
|
element_type: ''
|
||||||
element_class: ''
|
element_class: ''
|
||||||
|
element_label_type: ''
|
||||||
|
element_label_class: ''
|
||||||
|
element_label_colon: true
|
||||||
|
element_wrapper_type: ''
|
||||||
|
element_wrapper_class: ''
|
||||||
element_default_classes: true
|
element_default_classes: true
|
||||||
empty: ''
|
empty: ''
|
||||||
hide_empty: false
|
hide_empty: false
|
||||||
empty_zero: false
|
empty_zero: false
|
||||||
hide_alter_empty: true
|
hide_alter_empty: true
|
||||||
type: user_name
|
click_sort_column: target_id
|
||||||
|
type: entity_reference_label
|
||||||
|
settings:
|
||||||
|
link: true
|
||||||
|
group_column: target_id
|
||||||
|
group_columns: { }
|
||||||
|
group_rows: true
|
||||||
|
delta_limit: 0
|
||||||
|
delta_offset: 0
|
||||||
|
delta_reversed: false
|
||||||
|
delta_first_last: false
|
||||||
|
multi_type: separator
|
||||||
|
separator: ', '
|
||||||
|
field_api_classes: false
|
||||||
|
field_projets_curates:
|
||||||
|
id: field_projets_curates
|
||||||
|
table: node__field_projets_curates
|
||||||
|
field: field_projets_curates
|
||||||
|
relationship: none
|
||||||
|
group_type: group
|
||||||
|
admin_label: ''
|
||||||
|
plugin_id: field
|
||||||
|
label: projets_curates
|
||||||
|
exclude: false
|
||||||
|
alter:
|
||||||
|
alter_text: false
|
||||||
|
text: ''
|
||||||
|
make_link: false
|
||||||
|
path: ''
|
||||||
|
absolute: false
|
||||||
|
external: false
|
||||||
|
replace_spaces: false
|
||||||
|
path_case: none
|
||||||
|
trim_whitespace: false
|
||||||
|
alt: ''
|
||||||
|
rel: ''
|
||||||
|
link_class: ''
|
||||||
|
prefix: ''
|
||||||
|
suffix: ''
|
||||||
|
target: ''
|
||||||
|
nl2br: false
|
||||||
|
max_length: 0
|
||||||
|
word_boundary: true
|
||||||
|
ellipsis: true
|
||||||
|
more_link: false
|
||||||
|
more_link_text: ''
|
||||||
|
more_link_path: ''
|
||||||
|
strip_tags: false
|
||||||
|
trim: false
|
||||||
|
preserve_tags: ''
|
||||||
|
html: false
|
||||||
|
element_type: ''
|
||||||
|
element_class: ''
|
||||||
|
element_label_type: ''
|
||||||
|
element_label_class: ''
|
||||||
|
element_label_colon: true
|
||||||
|
element_wrapper_type: ''
|
||||||
|
element_wrapper_class: ''
|
||||||
|
element_default_classes: true
|
||||||
|
empty: ''
|
||||||
|
hide_empty: false
|
||||||
|
empty_zero: false
|
||||||
|
hide_alter_empty: true
|
||||||
|
click_sort_column: target_id
|
||||||
|
type: entity_reference_label
|
||||||
|
settings:
|
||||||
|
link: true
|
||||||
|
group_column: target_id
|
||||||
|
group_columns: { }
|
||||||
|
group_rows: true
|
||||||
|
delta_limit: 0
|
||||||
|
delta_offset: 0
|
||||||
|
delta_reversed: false
|
||||||
|
delta_first_last: false
|
||||||
|
multi_type: separator
|
||||||
|
separator: ', '
|
||||||
|
field_api_classes: false
|
||||||
status:
|
status:
|
||||||
id: status
|
id: status
|
||||||
table: node_field_data
|
table: node_field_data
|
||||||
@@ -658,9 +703,10 @@ display:
|
|||||||
columns:
|
columns:
|
||||||
node_bulk_form: node_bulk_form
|
node_bulk_form: node_bulk_form
|
||||||
type: title
|
type: title
|
||||||
field_prenom: title
|
|
||||||
title: title
|
title: title
|
||||||
name: name
|
field_type_de_projet: field_type_de_projet
|
||||||
|
field_projets_curates: field_projet_s_lie_s
|
||||||
|
field_projet_s_lie_s: field_projet_s_lie_s
|
||||||
status: status
|
status: status
|
||||||
changed: changed
|
changed: changed
|
||||||
operations: operations
|
operations: operations
|
||||||
@@ -678,13 +724,6 @@ display:
|
|||||||
separator: ''
|
separator: ''
|
||||||
empty_column: false
|
empty_column: false
|
||||||
responsive: ''
|
responsive: ''
|
||||||
field_prenom:
|
|
||||||
sortable: false
|
|
||||||
default_sort_order: asc
|
|
||||||
align: ''
|
|
||||||
separator: ''
|
|
||||||
empty_column: false
|
|
||||||
responsive: ''
|
|
||||||
title:
|
title:
|
||||||
sortable: true
|
sortable: true
|
||||||
default_sort_order: asc
|
default_sort_order: asc
|
||||||
@@ -692,13 +731,21 @@ display:
|
|||||||
separator: '<br/>'
|
separator: '<br/>'
|
||||||
empty_column: false
|
empty_column: false
|
||||||
responsive: ''
|
responsive: ''
|
||||||
name:
|
field_type_de_projet:
|
||||||
sortable: false
|
|
||||||
default_sort_order: asc
|
|
||||||
align: ''
|
align: ''
|
||||||
separator: ''
|
separator: ''
|
||||||
empty_column: false
|
empty_column: false
|
||||||
responsive: priority-low
|
responsive: ''
|
||||||
|
field_projets_curates:
|
||||||
|
align: ''
|
||||||
|
separator: ''
|
||||||
|
empty_column: false
|
||||||
|
responsive: ''
|
||||||
|
field_projet_s_lie_s:
|
||||||
|
align: ''
|
||||||
|
separator: ''
|
||||||
|
empty_column: false
|
||||||
|
responsive: ''
|
||||||
status:
|
status:
|
||||||
sortable: true
|
sortable: true
|
||||||
default_sort_order: asc
|
default_sort_order: asc
|
||||||
@@ -737,6 +784,17 @@ display:
|
|||||||
plugin_id: standard
|
plugin_id: standard
|
||||||
required: true
|
required: true
|
||||||
show_admin_links: false
|
show_admin_links: false
|
||||||
|
header:
|
||||||
|
result:
|
||||||
|
id: result
|
||||||
|
table: views
|
||||||
|
field: result
|
||||||
|
relationship: none
|
||||||
|
group_type: group
|
||||||
|
admin_label: ''
|
||||||
|
plugin_id: result
|
||||||
|
empty: false
|
||||||
|
content: 'Affichage de @start à @end sur @total'
|
||||||
display_extenders: { }
|
display_extenders: { }
|
||||||
cache_metadata:
|
cache_metadata:
|
||||||
max-age: 0
|
max-age: 0
|
||||||
@@ -749,7 +807,8 @@ display:
|
|||||||
- 'user.node_grants:view'
|
- 'user.node_grants:view'
|
||||||
- user.permissions
|
- user.permissions
|
||||||
tags:
|
tags:
|
||||||
- 'config:field.storage.node.field_prenom'
|
- 'config:field.storage.node.field_projet_s_lie_s'
|
||||||
|
- 'config:field.storage.node.field_projets_curates'
|
||||||
- 'config:field.storage.node.field_type_de_projet'
|
- 'config:field.storage.node.field_type_de_projet'
|
||||||
page_1:
|
page_1:
|
||||||
id: page_1
|
id: page_1
|
||||||
@@ -783,5 +842,6 @@ display:
|
|||||||
- 'user.node_grants:view'
|
- 'user.node_grants:view'
|
||||||
- user.permissions
|
- user.permissions
|
||||||
tags:
|
tags:
|
||||||
- 'config:field.storage.node.field_prenom'
|
- 'config:field.storage.node.field_projet_s_lie_s'
|
||||||
|
- 'config:field.storage.node.field_projets_curates'
|
||||||
- 'config:field.storage.node.field_type_de_projet'
|
- 'config:field.storage.node.field_type_de_projet'
|
||||||
|
|||||||
+30
-1
@@ -10,6 +10,10 @@ source:
|
|||||||
plugin: projet_node
|
plugin: projet_node
|
||||||
data_fetcher_plugin: http
|
data_fetcher_plugin: http
|
||||||
data_parser_plugin: google_sheets
|
data_parser_plugin: google_sheets
|
||||||
|
constants:
|
||||||
|
# Trailing slash: file_import keeps the original filename and copies the
|
||||||
|
# image into this directory.
|
||||||
|
images_destination: 'public://projets/'
|
||||||
# The feed file for the spreadsheet. The Google Spreadsheet should be either “Public” or set to “Anyone with link can
|
# The feed file for the spreadsheet. The Google Spreadsheet should be either “Public” or set to “Anyone with link can
|
||||||
# view” in order for the feed to work.
|
# view” in order for the feed to work.
|
||||||
# Template: 'https://sheets.googleapis.com/v4/spreadsheets/<SHEET>/values/<TAB>?key=<KEY>'
|
# Template: 'https://sheets.googleapis.com/v4/spreadsheets/<SHEET>/values/<TAB>?key=<KEY>'
|
||||||
@@ -68,7 +72,32 @@ process:
|
|||||||
type:
|
type:
|
||||||
plugin: default_value
|
plugin: default_value
|
||||||
default_value: projet
|
default_value: projet
|
||||||
title: title
|
title:
|
||||||
|
plugin: skip_on_empty
|
||||||
|
method: row
|
||||||
|
source: title
|
||||||
|
message: 'Projet ignoré : « Nom du projet » vide.'
|
||||||
|
body/value: body_html
|
||||||
|
body/format:
|
||||||
|
plugin: default_value
|
||||||
|
default_value: wysiwyg
|
||||||
|
field_images:
|
||||||
|
plugin: sub_process
|
||||||
|
source: images
|
||||||
|
process:
|
||||||
|
target_id:
|
||||||
|
plugin: image_resize_import
|
||||||
|
source: uri
|
||||||
|
destination: destination
|
||||||
|
max_width: 1920
|
||||||
|
max_height: 1920
|
||||||
|
reuse: true
|
||||||
|
skip_on_missing_source: true
|
||||||
|
alt: alt
|
||||||
|
image_field_caption/value: caption
|
||||||
|
image_field_caption/format:
|
||||||
|
plugin: default_value
|
||||||
|
default_value: wysiwyg
|
||||||
field_dates/value:
|
field_dates/value:
|
||||||
plugin: leshed_date
|
plugin: leshed_date
|
||||||
source: date_start
|
source: date_start
|
||||||
|
|||||||
@@ -0,0 +1,179 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Drupal\migrate_leshed\Plugin\migrate\process;
|
||||||
|
|
||||||
|
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||||
|
use Drupal\Core\File\FileSystemInterface;
|
||||||
|
use Drupal\Core\Image\ImageFactory;
|
||||||
|
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||||
|
use Drupal\migrate\Attribute\MigrateProcess;
|
||||||
|
use Drupal\migrate\MigrateExecutableInterface;
|
||||||
|
use Drupal\migrate\MigrateSkipRowException;
|
||||||
|
use Drupal\migrate\ProcessPluginBase;
|
||||||
|
use Drupal\migrate\Row;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies a local image, downscaling it to a web-friendly size, as a File.
|
||||||
|
*
|
||||||
|
* The source value is a readable file path/URI. The image is scaled down
|
||||||
|
* (aspect ratio preserved, never upscaled) to fit within max_width x
|
||||||
|
* max_height, saved into the destination directory and registered as a
|
||||||
|
* managed file. Returns the file id.
|
||||||
|
*
|
||||||
|
* Configuration:
|
||||||
|
* - destination: (required) destination directory URI, e.g. 'public://projets/1/'.
|
||||||
|
* - max_width: maximum width in pixels (default 1920).
|
||||||
|
* - max_height: maximum height in pixels (default 1920).
|
||||||
|
* - uid: owner uid of the created file (default 0).
|
||||||
|
* - reuse: reuse an existing managed file at the destination URI (default TRUE).
|
||||||
|
* - skip_on_missing_source: skip the value when the source is missing
|
||||||
|
* (default TRUE) instead of failing.
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* field_images/target_id:
|
||||||
|
* plugin: image_resize_import
|
||||||
|
* source: uri
|
||||||
|
* destination: destination
|
||||||
|
* max_width: 1920
|
||||||
|
* max_height: 1920
|
||||||
|
* @endcode
|
||||||
|
*/
|
||||||
|
#[MigrateProcess(id: 'image_resize_import')]
|
||||||
|
final class ImageResizeImport extends ProcessPluginBase implements ContainerFactoryPluginInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Per-run cache of already resolved destination URIs to file ids.
|
||||||
|
*
|
||||||
|
* @var array<string, int>
|
||||||
|
*/
|
||||||
|
private array $fidCache = [];
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
array $configuration,
|
||||||
|
$plugin_id,
|
||||||
|
$plugin_definition,
|
||||||
|
private readonly FileSystemInterface $fileSystem,
|
||||||
|
private readonly ImageFactory $imageFactory,
|
||||||
|
private readonly EntityTypeManagerInterface $entityTypeManager,
|
||||||
|
) {
|
||||||
|
$configuration += [
|
||||||
|
'max_width' => 1920,
|
||||||
|
'max_height' => 1920,
|
||||||
|
'uid' => 0,
|
||||||
|
'reuse' => TRUE,
|
||||||
|
'skip_on_missing_source' => TRUE,
|
||||||
|
];
|
||||||
|
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): self {
|
||||||
|
return new self(
|
||||||
|
$configuration,
|
||||||
|
$plugin_id,
|
||||||
|
$plugin_definition,
|
||||||
|
$container->get('file_system'),
|
||||||
|
$container->get('image.factory'),
|
||||||
|
$container->get('entity_type.manager'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property): ?int {
|
||||||
|
$source = is_string($value) ? trim($value) : '';
|
||||||
|
if ($source === '') {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stream wrappers support is_file() directly; realpath() is only needed as
|
||||||
|
// a fallback for schemes it cannot resolve.
|
||||||
|
if (!is_file($source) && !is_file($this->fileSystem->realpath($source) ?: $source)) {
|
||||||
|
// Skipping throws MigrateSkipRowException because, inside a sub_process,
|
||||||
|
// only that exception drops the whole image item cleanly (SubProcess
|
||||||
|
// catches it and `continue`s); MigrateSkipProcessException would instead
|
||||||
|
// leave a broken delta with alt/caption but no target_id.
|
||||||
|
return $this->skipImage($migrate_executable, "Source image '$source' is missing.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$directory = $this->getPropertyValue($this->configuration['destination'], $row);
|
||||||
|
if (!is_string($directory) || $directory === '') {
|
||||||
|
return $this->skipImage($migrate_executable, "Missing 'destination' for image '$source'.");
|
||||||
|
}
|
||||||
|
$directory = rtrim($directory, '/') . '/';
|
||||||
|
$destination = $directory . $this->fileSystem->basename($source);
|
||||||
|
|
||||||
|
// Reuse an already imported file (idempotency), memoized for the run.
|
||||||
|
if ($this->configuration['reuse']) {
|
||||||
|
if (isset($this->fidCache[$destination])) {
|
||||||
|
return $this->fidCache[$destination];
|
||||||
|
}
|
||||||
|
$existing = $this->entityTypeManager->getStorage('file')
|
||||||
|
->loadByProperties(['uri' => $destination]);
|
||||||
|
if ($existing) {
|
||||||
|
return $this->fidCache[$destination] = (int) reset($existing)->id();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any infrastructure failure only drops the current image (logged), so a
|
||||||
|
// single unreadable/oversized file never aborts the whole batch.
|
||||||
|
try {
|
||||||
|
if (!$this->fileSystem->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS)) {
|
||||||
|
return $this->skipImage($migrate_executable, "Cannot prepare directory '$directory'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$image = $this->imageFactory->get($source);
|
||||||
|
if (!$image->isValid()) {
|
||||||
|
return $this->skipImage($migrate_executable, "Source '$source' is not a valid image.");
|
||||||
|
}
|
||||||
|
// Downscale only: scale() never upscales when upscale is FALSE.
|
||||||
|
$image->scale((int) $this->configuration['max_width'], (int) $this->configuration['max_height']);
|
||||||
|
if (!$image->save($destination)) {
|
||||||
|
return $this->skipImage($migrate_executable, "Failed to write resized image to '$destination'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = $this->entityTypeManager->getStorage('file')->create([
|
||||||
|
'uri' => $destination,
|
||||||
|
'uid' => (int) $this->getPropertyValue($this->configuration['uid'], $row),
|
||||||
|
'status' => 1,
|
||||||
|
]);
|
||||||
|
$file->save();
|
||||||
|
}
|
||||||
|
catch (\Throwable $e) {
|
||||||
|
return $this->skipImage($migrate_executable, "Import of image '$source' failed: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->fidCache[$destination] = (int) $file->id();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs a message and skips the current image item.
|
||||||
|
*
|
||||||
|
* @throws \Drupal\migrate\MigrateSkipRowException
|
||||||
|
*/
|
||||||
|
private function skipImage(MigrateExecutableInterface $migrate_executable, string $message): never {
|
||||||
|
$migrate_executable->saveMessage($message);
|
||||||
|
throw new MigrateSkipRowException($message, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves a configuration value, supporting destination (@) references.
|
||||||
|
*/
|
||||||
|
private function getPropertyValue(mixed $key, Row $row): mixed {
|
||||||
|
if (is_string($key) && str_starts_with($key, '@')) {
|
||||||
|
return $row->get(substr($key, 1));
|
||||||
|
}
|
||||||
|
if (is_string($key) && $row->hasSourceProperty($key)) {
|
||||||
|
return $row->getSourceProperty($key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $key;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -18,8 +18,9 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||||||
* Input: a string such as "Julie Faitot et Jonathan Loppin" or
|
* Input: a string such as "Julie Faitot et Jonathan Loppin" or
|
||||||
* "Sonja Beaudouin, Alexandre Delabrière". Names are split on "et" and
|
* "Sonja Beaudouin, Alexandre Delabrière". Names are split on "et" and
|
||||||
* commas. For each name, the first word is used as 'field_prenom' and the
|
* commas. For each name, the first word is used as 'field_prenom' and the
|
||||||
* rest as the node title. An existing node with the same title and prenom
|
* rest as 'field_nom'. The node title is generated from those two fields by
|
||||||
* is reused, otherwise it is created. Returns an array of node IDs.
|
* the auto_entitylabel module on save. An existing node with the same nom and
|
||||||
|
* prenom is reused, otherwise it is created. Returns an array of node IDs.
|
||||||
*
|
*
|
||||||
* When 'type_de_personne' is set in the configuration, a taxonomy term with
|
* When 'type_de_personne' is set in the configuration, a taxonomy term with
|
||||||
* that name is found or created (without duplicates) in the
|
* that name is found or created (without duplicates) in the
|
||||||
@@ -103,7 +104,7 @@ final class PersonneGenerate extends ProcessPluginBase implements ContainerFacto
|
|||||||
|
|
||||||
$query = $storage->getQuery()
|
$query = $storage->getQuery()
|
||||||
->condition('type', 'personne')
|
->condition('type', 'personne')
|
||||||
->condition('title', $nom)
|
->condition('field_nom', $nom)
|
||||||
->accessCheck(FALSE)
|
->accessCheck(FALSE)
|
||||||
->range(0, 1);
|
->range(0, 1);
|
||||||
if ($prenom !== '') {
|
if ($prenom !== '') {
|
||||||
@@ -121,9 +122,11 @@ final class PersonneGenerate extends ProcessPluginBase implements ContainerFacto
|
|||||||
return $nid;
|
return $nid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The node title is generated from field_prenom + field_nom by
|
||||||
|
// auto_entitylabel on save; it is intentionally not set here.
|
||||||
$values = [
|
$values = [
|
||||||
'type' => 'personne',
|
'type' => 'personne',
|
||||||
'title' => $nom,
|
'field_nom' => $nom,
|
||||||
'field_prenom' => $prenom === '' ? NULL : $prenom,
|
'field_prenom' => $prenom === '' ? NULL : $prenom,
|
||||||
'status' => 1,
|
'status' => 1,
|
||||||
'uid' => $this->configuration['author_uid'] ?? 3,
|
'uid' => $this->configuration['author_uid'] ?? 3,
|
||||||
|
|||||||
@@ -4,11 +4,31 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Drupal\migrate_leshed\Plugin\migrate\source;
|
namespace Drupal\migrate_leshed\Plugin\migrate\source;
|
||||||
|
|
||||||
|
use Drupal\Core\File\FileSystemInterface;
|
||||||
use Drupal\migrate\Attribute\MigrateSource;
|
use Drupal\migrate\Attribute\MigrateSource;
|
||||||
use Drupal\migrate_plus\Plugin\migrate\source\Url;
|
use Drupal\migrate\Plugin\MigrationInterface;
|
||||||
use Drupal\migrate\Row;
|
use Drupal\migrate\Row;
|
||||||
|
use Drupal\migrate_plus\DataParserPluginManager;
|
||||||
|
use Drupal\migrate_plus\Plugin\migrate\source\Url;
|
||||||
|
use League\CommonMark\CommonMarkConverter;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Source plugin for projects, enriched with body and images from the drive.
|
||||||
|
*
|
||||||
|
* On top of the Google Sheets columns, this source reads the local files
|
||||||
|
* synced from the shared Google Drive (see the `sync_leshed_drive` Makefile
|
||||||
|
* target) that live under public://drive_shared_leshed. Files are grouped in
|
||||||
|
* per-project folders named "Page{UID}" (optionally suffixed, e.g.
|
||||||
|
* "Page1_Complet"), where {UID} matches the sheet UID column:
|
||||||
|
* - "{UID}_texte_*.md": the body, written in Markdown, converted to HTML.
|
||||||
|
* - "{UID}_images|Images/": one folder of images, each "{name}.jpg" paired
|
||||||
|
* with a "{name}_legende.md" caption used as the (required) alt text.
|
||||||
|
*
|
||||||
|
* These are exposed as two extra source properties consumed by the migration:
|
||||||
|
* - body_html: the converted HTML string (or NULL).
|
||||||
|
* - images: a list of ['uri' => string, 'alt' => string] items.
|
||||||
|
*
|
||||||
* @MigrateSource(
|
* @MigrateSource(
|
||||||
* id = "projet_node"
|
* id = "projet_node"
|
||||||
* )
|
* )
|
||||||
@@ -16,18 +36,65 @@ use Drupal\migrate\Row;
|
|||||||
#[MigrateSource(id: 'projet_node')]
|
#[MigrateSource(id: 'projet_node')]
|
||||||
final class ProjetNode extends Url {
|
final class ProjetNode extends Url {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stream wrapper URI of the synced drive folder.
|
||||||
|
*/
|
||||||
|
private const DRIVE_URI = 'public://drive_shared_leshed';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Image file extensions to import into field_images.
|
||||||
|
*/
|
||||||
|
private const IMAGE_EXTENSIONS = ['png', 'gif', 'jpg', 'jpeg', 'webp'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default destination directory when no constant is configured.
|
||||||
|
*/
|
||||||
|
private const DEFAULT_IMAGE_DESTINATION = 'public://projets/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lazily instantiated Markdown converter.
|
||||||
|
*/
|
||||||
|
private ?CommonMarkConverter $markdownConverter = NULL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Memoized map of UID => project folder URI, built once from the drive root.
|
||||||
|
*
|
||||||
|
* @var array<string, string>|null
|
||||||
|
*/
|
||||||
|
private ?array $folderMap = NULL;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
array $configuration,
|
||||||
|
$plugin_id,
|
||||||
|
$plugin_definition,
|
||||||
|
MigrationInterface $migration,
|
||||||
|
DataParserPluginManager $parserPluginManager,
|
||||||
|
private readonly FileSystemInterface $fileSystem,
|
||||||
|
) {
|
||||||
|
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $parserPluginManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function create($container, array $configuration, $plugin_id, $plugin_definition, ?MigrationInterface $migration = NULL): self {
|
||||||
|
return new self(
|
||||||
|
$configuration,
|
||||||
|
$plugin_id,
|
||||||
|
$plugin_definition,
|
||||||
|
$migration,
|
||||||
|
$container->get('plugin.manager.migrate_plus.data_parser'),
|
||||||
|
$container->get('file_system'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function fields(): array {
|
public function fields(): array {
|
||||||
// theese are source fields
|
return parent::fields() + [
|
||||||
return [
|
'body_html' => $this->t('Project body (HTML converted from Markdown)'),
|
||||||
'id' => $this->t('Project ID'),
|
'images' => $this->t('Project images with captions'),
|
||||||
'title' => $this->t('Project Title'),
|
|
||||||
'date_start' => $this->t('Project date start'),
|
|
||||||
'date_end' => $this->t('Project date end'),
|
|
||||||
'projet_type' => $this->t('Type de projet'),
|
|
||||||
'curator' => $this->t('Commissaria')
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,16 +112,211 @@ final class ProjetNode extends Url {
|
|||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function prepareRow(Row $row) {
|
public function prepareRow(Row $row): bool {
|
||||||
// $nid = $row->getSourceProperty('entity_id');
|
// Let the parent (and prepare-row event subscribers) decide first: no need
|
||||||
// $vid = $row->getSourceProperty('revision_id');
|
// to hit the filesystem for a row that will be skipped.
|
||||||
// $type = $row->getSourceProperty('type');
|
if (!parent::prepareRow($row)) {
|
||||||
// $language = $row->getSourceProperty('language');
|
return FALSE;
|
||||||
// $title = $row->getSourceProperty('title');
|
}
|
||||||
// // drush_print('-- '.$nid."\t".$title."\t".$language);
|
|
||||||
|
|
||||||
|
// Always define both properties so the process pipeline never references
|
||||||
|
// an undefined source key, even when no drive folder exists yet.
|
||||||
|
$row->setSourceProperty('body_html', NULL);
|
||||||
|
$row->setSourceProperty('images', []);
|
||||||
|
|
||||||
|
$uid = trim((string) $row->getSourceProperty('id'));
|
||||||
|
$folder = $uid !== '' ? $this->findProjectFolder($uid) : NULL;
|
||||||
|
if ($folder !== NULL) {
|
||||||
|
$row->setSourceProperty('body_html', $this->readBody($folder, $uid));
|
||||||
|
$row->setSourceProperty('images', $this->readImages($folder, $uid, (string) $row->getSourceProperty('title')));
|
||||||
|
}
|
||||||
|
|
||||||
return parent::prepareRow($row);
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the public:// URI of the project folder, or NULL when missing.
|
||||||
|
*/
|
||||||
|
private function findProjectFolder(string $uid): ?string {
|
||||||
|
return $this->getFolderMap()[$uid] ?? NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds (once) the UID => project folder URI map from the drive root.
|
||||||
|
*
|
||||||
|
* @return array<string, string>
|
||||||
|
* Map keyed by the numeric part of each "Page{UID}[_suffix]" folder.
|
||||||
|
*/
|
||||||
|
private function getFolderMap(): array {
|
||||||
|
if ($this->folderMap !== NULL) {
|
||||||
|
return $this->folderMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->folderMap = [];
|
||||||
|
$base = $this->fileSystem->realpath(self::DRIVE_URI);
|
||||||
|
if ($base === FALSE || !is_dir($base)) {
|
||||||
|
return $this->folderMap;
|
||||||
|
}
|
||||||
|
// Match "Page{N}" exactly or with a suffix ("_Complet", ...). Sorting keeps
|
||||||
|
// the resolution deterministic when e.g. "Page5" and "Page5_Complet"
|
||||||
|
// coexist (the plain, longer-suffixed folder wins consistently).
|
||||||
|
$entries = scandir($base) ?: [];
|
||||||
|
sort($entries, SORT_NATURAL | SORT_FLAG_CASE);
|
||||||
|
foreach ($entries as $entry) {
|
||||||
|
if ($entry === '.' || $entry === '..' || !is_dir($base . '/' . $entry)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (preg_match('/^Page(\d+)(_.*)?$/', $entry, $matches)) {
|
||||||
|
$this->folderMap[$matches[1]] = self::DRIVE_URI . '/' . $entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $this->folderMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the Markdown body file and converts it to HTML.
|
||||||
|
*/
|
||||||
|
private function readBody(string $folderUri, string $uid): ?string {
|
||||||
|
$dir = $this->fileSystem->realpath($folderUri);
|
||||||
|
if ($dir === FALSE) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
// Prefer "{UID}_texte*.md", fall back to any Markdown file at the root.
|
||||||
|
$preferred = '/^' . preg_quote($uid, '/') . '_texte.*\.md$/i';
|
||||||
|
$entries = scandir($dir) ?: [];
|
||||||
|
sort($entries, SORT_NATURAL | SORT_FLAG_CASE);
|
||||||
|
$markdown = NULL;
|
||||||
|
foreach ($entries as $entry) {
|
||||||
|
if (!is_file($dir . '/' . $entry) || !preg_match('/\.md$/i', $entry)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (preg_match($preferred, $entry)) {
|
||||||
|
$markdown = $dir . '/' . $entry;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$markdown ??= $dir . '/' . $entry;
|
||||||
|
}
|
||||||
|
if ($markdown === NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
$contents = file_get_contents($markdown);
|
||||||
|
if ($contents === FALSE || trim($contents) === '') {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (string) $this->getMarkdownConverter()->convert($contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the list of images (URI + alt) for the project.
|
||||||
|
*
|
||||||
|
* @return array<int, array{uri: string, alt: string, caption: string, destination: string}>
|
||||||
|
* The images to import.
|
||||||
|
*/
|
||||||
|
private function readImages(string $folderUri, string $uid, string $title): array {
|
||||||
|
$dir = $this->fileSystem->realpath($folderUri);
|
||||||
|
if ($dir === FALSE) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
// The destination is passed through each item because a sub_process row
|
||||||
|
// cannot read the parent migration's `constants`. It is namespaced per
|
||||||
|
// project (UID) so identically-named files from different projects never
|
||||||
|
// collide when file_import reuses existing files (reuse: true).
|
||||||
|
$base = $this->configuration['constants']['images_destination']
|
||||||
|
?? self::DEFAULT_IMAGE_DESTINATION;
|
||||||
|
$destination = rtrim($base, '/') . '/' . $uid . '/';
|
||||||
|
// Locate the images subfolder ("{UID}_images", case-insensitive).
|
||||||
|
$imagesDirUri = NULL;
|
||||||
|
$pattern = '/^' . preg_quote($uid, '/') . '_images$/i';
|
||||||
|
foreach (scandir($dir) ?: [] as $entry) {
|
||||||
|
if (preg_match($pattern, $entry) && is_dir($dir . '/' . $entry)) {
|
||||||
|
$imagesDirUri = $folderUri . '/' . $entry;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($imagesDirUri === NULL) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$imagesDir = $this->fileSystem->realpath($imagesDirUri);
|
||||||
|
if ($imagesDir === FALSE) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
$images = [];
|
||||||
|
$files = scandir($imagesDir) ?: [];
|
||||||
|
sort($files, SORT_NATURAL | SORT_FLAG_CASE);
|
||||||
|
foreach ($files as $file) {
|
||||||
|
$extension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
|
||||||
|
if (!in_array($extension, self::IMAGE_EXTENSIONS, TRUE)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$name = pathinfo($file, PATHINFO_FILENAME);
|
||||||
|
$legende = $this->readCaptionFile($imagesDir . '/' . $name . '_legende.md');
|
||||||
|
// Plain text (required alt), falling back to the project title. Capped to
|
||||||
|
// the image field's alt column length (varchar 512).
|
||||||
|
$alt = $legende !== '' ? $this->toPlainText($legende) : $title;
|
||||||
|
$alt = mb_substr($alt, 0, 512);
|
||||||
|
// Rich caption (image_field_caption): Markdown converted to HTML.
|
||||||
|
$caption = $legende !== '' ? (string) $this->getMarkdownConverter()->convert($legende) : '';
|
||||||
|
$images[] = [
|
||||||
|
'uri' => $imagesDirUri . '/' . $file,
|
||||||
|
'alt' => $alt,
|
||||||
|
'caption' => $caption,
|
||||||
|
'destination' => $destination,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $images;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the raw contents of a caption (legende) file, or '' when missing.
|
||||||
|
*/
|
||||||
|
private function readCaptionFile(string $captionPath): string {
|
||||||
|
if (!is_file($captionPath)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
$contents = file_get_contents($captionPath);
|
||||||
|
if ($contents === FALSE) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
// Drive exports are occasionally Windows-1252 rather than UTF-8.
|
||||||
|
if (!mb_check_encoding($contents, 'UTF-8')) {
|
||||||
|
$contents = mb_convert_encoding($contents, 'UTF-8', 'Windows-1252');
|
||||||
|
}
|
||||||
|
|
||||||
|
return trim($contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reduces Markdown/HTML text to a single trimmed plain-text line (for alt).
|
||||||
|
*/
|
||||||
|
private function toPlainText(string $text): string {
|
||||||
|
$text = html_entity_decode(strip_tags($text), ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
||||||
|
// Drop Markdown emphasis/heading markers left after tag stripping.
|
||||||
|
$text = preg_replace('/[*_#`>]+/u', '', $text) ?? $text;
|
||||||
|
|
||||||
|
return trim((string) preg_replace('/\s+/u', ' ', $text));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the shared Markdown converter.
|
||||||
|
*
|
||||||
|
* Raw HTML embedded in the source Markdown (alignment <div>, <br>, ...) is
|
||||||
|
* stripped: only the Markdown itself is converted to HTML, keeping the body
|
||||||
|
* clean and safe for the wysiwyg format.
|
||||||
|
*/
|
||||||
|
private function getMarkdownConverter(): CommonMarkConverter {
|
||||||
|
if ($this->markdownConverter === NULL) {
|
||||||
|
$this->markdownConverter = new CommonMarkConverter([
|
||||||
|
'html_input' => 'strip',
|
||||||
|
'allow_unsafe_links' => FALSE,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->markdownConverter;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
{#
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Default theme implementation to display a node.
|
||||||
|
*
|
||||||
|
* Available variables:
|
||||||
|
* - node: The node entity with limited access to object properties and methods.
|
||||||
|
* Only method names starting with "get", "has", or "is" and a few common
|
||||||
|
* methods such as "id", "label", and "bundle" are available. For example:
|
||||||
|
* - node.getCreatedTime() will return the node creation timestamp.
|
||||||
|
* - node.hasField('field_example') returns TRUE if the node bundle includes
|
||||||
|
* field_example. (This does not indicate the presence of a value in this
|
||||||
|
* field.)
|
||||||
|
* - node.isPublished() will return whether the node is published or not.
|
||||||
|
* Calling other methods, such as node.delete(), will result in an exception.
|
||||||
|
* See \Drupal\node\Entity\Node for a full list of public properties and
|
||||||
|
* methods for the node object.
|
||||||
|
* - label: (optional) The title of the node.
|
||||||
|
* - content: All node items. Use {{ content }} to print them all,
|
||||||
|
* or print a subset such as {{ content.field_example }}. Use
|
||||||
|
* {{ content|without('field_example') }} to temporarily suppress the printing
|
||||||
|
* of a given child element.
|
||||||
|
* - author_picture: The node author user entity, rendered using the "compact"
|
||||||
|
* view mode.
|
||||||
|
* - metadata: Metadata for this node.
|
||||||
|
* - date: (optional) Themed creation date field.
|
||||||
|
* - author_name: (optional) Themed author name field.
|
||||||
|
* - url: Direct URL of the current node.
|
||||||
|
* - display_submitted: Whether submission information should be displayed.
|
||||||
|
* - attributes: HTML attributes for the containing element.
|
||||||
|
* The attributes.class element may contain one or more of the following
|
||||||
|
* classes:
|
||||||
|
* - node: The current template type (also known as a "theming hook").
|
||||||
|
* - node--type-[type]: The current node type. For example, if the node is an
|
||||||
|
* "Article" it would result in "node--type-article". Note that the machine
|
||||||
|
* name will often be in a short form of the human readable label.
|
||||||
|
* - node--view-mode-[view_mode]: The View Mode of the node; for example, a
|
||||||
|
* teaser would result in: "node--view-mode-teaser", and
|
||||||
|
* full: "node--view-mode-full".
|
||||||
|
* The following are controlled through the node publishing options.
|
||||||
|
* - node--promoted: Appears on nodes promoted to the front page.
|
||||||
|
* - node--sticky: Appears on nodes ordered above other non-sticky nodes in
|
||||||
|
* teaser listings.
|
||||||
|
* - node--unpublished: Appears on unpublished nodes visible only to site
|
||||||
|
* admins.
|
||||||
|
* - title_attributes: Same as attributes, except applied to the main title
|
||||||
|
* tag that appears in the template.
|
||||||
|
* - content_attributes: Same as attributes, except applied to the main
|
||||||
|
* content tag that appears in the template.
|
||||||
|
* - author_attributes: Same as attributes, except applied to the author of
|
||||||
|
* the node tag that appears in the template.
|
||||||
|
* - title_prefix: Additional output populated by modules, intended to be
|
||||||
|
* displayed in front of the main title tag that appears in the template.
|
||||||
|
* - title_suffix: Additional output populated by modules, intended to be
|
||||||
|
* displayed after the main title tag that appears in the template.
|
||||||
|
* - view_mode: View mode; for example, "teaser" or "full".
|
||||||
|
* - teaser: Flag for the teaser state. Will be true if view_mode is 'teaser'.
|
||||||
|
* - page: Flag for the full page state. Will be true if view_mode is 'full'.
|
||||||
|
*
|
||||||
|
* @see template_preprocess_node()
|
||||||
|
*
|
||||||
|
* @ingroup themeable
|
||||||
|
*/
|
||||||
|
#}
|
||||||
|
<article{{ attributes }}>
|
||||||
|
|
||||||
|
{{ title_prefix }}
|
||||||
|
{% if label and not page %}
|
||||||
|
<h2{{ title_attributes }}>
|
||||||
|
<a href="{{ url }}" rel="bookmark">{{ label }}</a>
|
||||||
|
</h2>
|
||||||
|
{% endif %}
|
||||||
|
{{ title_suffix }}
|
||||||
|
|
||||||
|
{% if display_submitted %}
|
||||||
|
<footer>
|
||||||
|
{{ author_picture }}
|
||||||
|
<div{{ author_attributes }}>
|
||||||
|
{% trans %}Submitted by {{ author_name }} on {{ date }}{% endtrans %}
|
||||||
|
{{ metadata }}
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div{{ content_attributes }}>
|
||||||
|
{{ content }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</article>
|
||||||
Reference in New Issue
Block a user