From 86da5dd72741a064a842de486163d85cf6f394fc Mon Sep 17 00:00:00 2001 From: nicod_ <nicod@lerebooteux.fr> Date: Thu, 16 Nov 2023 17:52:03 +0100 Subject: [PATCH] =?UTF-8?q?feat(WIP):=20V2=20avec=20rupture=20de=20compati?= =?UTF-8?q?bilit=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Les blocktypes ne sont plus gérés dans le privé avec une table dédiée et un constructeur de formulaires, mais se basent sur des fichiers blocks/*.yaml (comme saisies, compositions, inserer_modele etc.) Une procédure de mise à jour / migration est prévue, cf README.md --- README.md | 13 +++ TODO.md | 14 +-- base/blocks.php | 81 ++------------ blocks_administrations.php | 62 ++++------- formulaires/exporter_blocktypes.html | 30 +++++ formulaires/exporter_blocktypes.php | 111 +++++++++++++++++++ formulaires/supprimer_blocktypes.html | 26 +++++ formulaires/supprimer_blocktypes.php | 26 +++++ paquet.xml | 4 +- prive/squelettes/contenu/update_blocks2.html | 13 +++ 10 files changed, 256 insertions(+), 124 deletions(-) create mode 100644 formulaires/exporter_blocktypes.html create mode 100644 formulaires/exporter_blocktypes.php create mode 100644 formulaires/supprimer_blocktypes.html create mode 100644 formulaires/supprimer_blocktypes.php create mode 100644 prive/squelettes/contenu/update_blocks2.html diff --git a/README.md b/README.md index bae5074..5330048 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,19 @@ Un plugin pour composer des pages sous forme de blocs, rangés les uns à la sui **[WIP]** En cours de développement, des choses peuvent bouger de façon significative (cf TODO.md) +## Mise à jour / migration en v2 + +Les types de blocks ne sont plus gérés en wysiwyg dans l'espace privé avec un constructeur de formulaire.\ +On se base plutôt sur le même fonctionnement que inserer_modeles, saisies ou compostions, en cherchant des fichiers .yaml dans les répertoires 'blocks' des squelettes. + +Les tables spip_blocktypes et spip_blocktypes_liens ne sont donc plus utilisées. + +Une procédure de mise à jour est prévue : dans l'espace privé, rendez vous sur ecrire/?exec=update_blocks2 qui vous permettra : +* d'exporter tous les types de blocks existant en yaml dans un répertoire +* de supprimer les tables inutiles + +## Description + Chaque type de bloc a un identifiant unique (slug), qui permet de chercher un squelette dans le path sous la forme blocks/identifiant.html, sinon on prend blocks/dist.html\ Dans le privé, on cherche d'abord blocks_prive/identifiant.html, ce qui permet d'avoir un affichage différent dans l'espace privé du site public (espace plus réduit en largeur, pas les même css ou js chargés) diff --git a/TODO.md b/TODO.md index 5acfd87..94e56c6 100644 --- a/TODO.md +++ b/TODO.md @@ -13,32 +13,26 @@ **Technique** +[ ] Pouvoir brancher un type de block sur un modèle auto-documenté (html + yaml) : un blocks/modele_*.yaml spécifique qui référence le modèle ? + [ ] Pouvoir restreindre l'utilisation de certains types de blocs à certains objets - ajouter un critère sur les boucles blocks ou modifier ces boucles en pipeline pour ne remonter que les blocs dont les types sont associables à l'objet en cours [ ] Si le type de block est associable aux rubriques, pouvoir restreindre son utilisation à une branche - remarque idem point précédent -[ ] Pouvoir brancher un type de block sur un modèle auto-documenté (html + yaml), ou un blocks/*.yaml spécifique -- continuer à utiliser en parallèle le constructeur de formulaire ? il est quand même très pratique - [ ] Gestion de champs de type fichiers : comment les associer aux blocks ? - comme des documents liés dont l'id est référencé dans la valeur du champ, en plus d'un lien dans spip_documents_liens ? (hum...) - avec des rôles dynamiques ? (hum...) **UX** -[ ] Créer quelques blocks types à l'installation +[ ] Créer quelques types de blocks de démo en .yaml + .html dans demo/blocks - Texte simple avec titre optionnel + niveaux de titre -- ... +- Bloc conteneur + bloc enfant ## Questions -[ ] Saisie blocktypes : utilisation de leurs logos comme illustrations d'exemples de mise en page ? - -[ ] Une config pour insérer directement les blocks dans la balise #TEXTE des articles, pour ne pas nécessiter de modification de squelette et pour que TEXTE renvoie tout le temps le contenu complet (texte + block) -- quid des autres objets - [ ] Pouvoir détacher un block d'un objet et le rattacher à un autre objet ? [ ] CSS : charger (privé et public) un blocks/identifiant.css ou html.css ou scss ? diff --git a/base/blocks.php b/base/blocks.php index 0c005fa..b8688c3 100644 --- a/base/blocks.php +++ b/base/blocks.php @@ -25,7 +25,6 @@ if (!defined('_ECRIRE_INC_VERSION')) { function blocks_declarer_tables_interfaces($interfaces) { $interfaces['table_des_tables']['blocks'] = 'blocks'; - $interfaces['table_des_tables']['blocktypes'] = 'blocktypes'; return $interfaces; } @@ -46,7 +45,7 @@ function blocks_declarer_tables_objets_sql($tables) { 'principale' => 'oui', 'field' => [ 'id_block' => 'bigint(21) NOT NULL', - 'id_blocktype' => 'bigint(21) NOT NULL DEFAULT 0', + 'blocktype' => 'varchar(255) DEFAULT "" NOT NULL', 'objet' => 'varchar(25) DEFAULT "" NOT NULL', 'id_objet' => 'bigint(21) DEFAULT "0" NOT NULL', 'rang_lien' => 'int(4) DEFAULT "0" NOT NULL', @@ -57,17 +56,16 @@ function blocks_declarer_tables_objets_sql($tables) { 'maj' => 'timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP', ], 'key' => [ - 'PRIMARY KEY' => 'id_block', - 'KEY id_blocktype' => 'id_blocktype', - 'KEY objet' => 'objet', - 'KEY id_objet' => 'id_objet', - 'KEY statut' => 'statut', + 'PRIMARY KEY' => 'id_block', + 'KEY blocktype' => 'blocktype', + 'KEY objet' => 'objet', + 'KEY id_objet' => 'id_objet', + 'KEY statut' => 'statut', ], 'titre' => 'id_blocktype AS titre', 'date' => 'date', - 'champs_editables' => ['id_blocktype', 'id_objet', 'objet', 'ancre'], - 'champs_versionnes' => ['id_blocktype', 'id_objet', 'objet', 'ancre', 'valeurs'], - 'tables_jointures' => ['spip_blocktypes'], + 'champs_editables' => ['blocktype', 'id_objet', 'objet', 'ancre'], + 'champs_versionnes' => ['blocktype', 'id_objet', 'objet', 'ancre', 'valeurs'], 'statut_textes_instituer' => [ 'prepa' => 'texte_statut_en_cours_redaction', 'prop' => 'texte_statut_propose_evaluation', @@ -88,71 +86,8 @@ function blocks_declarer_tables_objets_sql($tables) { 'page' => false, ]; - $tables['spip_blocktypes'] = [ - 'type' => 'blocktype', - 'principale' => 'oui', - 'field' => [ - 'id_blocktype' => 'bigint(21) NOT NULL', - 'titre' => 'text NOT NULL DEFAULT ""', - 'description' => 'text NOT NULL DEFAULT ""', - 'identifiant' => 'varchar(255) NOT NULL DEFAULT ""', - 'saisies' => 'text NOT NULL DEFAULT ""', - 'objets' => 'text NOT NULL DEFAULT ""', - 'maj' => 'timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP', - ], - 'key' => [ - 'PRIMARY KEY' => 'id_blocktype', - 'UNIQUE KEY identifiant' => 'identifiant', - ], - 'titre' => 'titre AS titre, "" AS lang', - 'champs_editables' => ['titre', 'description', 'saisies', 'objets', 'identifiant'], - 'champs_versionnes' => ['titre', 'description', 'saisies', 'objets', 'identifiant'], - 'rechercher_champs' => ["titre" => 10, 'description' => 5, 'identifiant' => 5], - 'tables_jointures' => [], - 'roles_titres' => [ - 'enfant' => _T('blocktype:role_enfant'), - 'parent' => _T('blocktype:role_parent'), - ], - 'roles_objets' => [ - 'blocktypes' => [ - 'choix' => ['enfant', 'parent'], - 'defaut' => '', - ], - ], - 'page' => false, - ]; - // jointure potentielle avec tous les objets $tables[]['tables_jointures'][] = 'blocks'; return $tables; } - -/** - * Déclaration des tables secondaires (liaisons) - * - * @pipeline declarer_tables_auxiliaires - * @param array $tables - * Description des tables - * @return array - * Description complétée des tables - */ -function blocks_declarer_tables_auxiliaires($tables) { - - // table de liaison entre blocktypes enfants / parents - $tables['spip_blocktypes_liens'] = [ - 'field' => [ - 'id_blocktype' => 'bigint(21) DEFAULT "0" NOT NULL', - 'id_objet' => 'bigint(21) DEFAULT "0" NOT NULL', - 'objet' => 'varchar(25) DEFAULT "" NOT NULL', - 'rang_lien' => 'int(4) DEFAULT "0" NOT NULL', - 'role' => 'varchar(25) DEFAULT "" NOT NULL', // [enfant|parent] - ], - 'key' => [ - 'PRIMARY KEY' => 'id_blocktype,id_objet,objet,role', - 'KEY id_blocktype' => 'id_blocktype', - ], - ]; - - return $tables; -} diff --git a/blocks_administrations.php b/blocks_administrations.php index 39a2d92..385095d 100644 --- a/blocks_administrations.php +++ b/blocks_administrations.php @@ -45,6 +45,12 @@ function blocks_upgrade($nom_meta_base_version, $version_cible) { ['sql_drop_table', 'spip_blocks_liens'], ]; + $maj['2.0.0'] = [ + ['sql_alter', 'TABLE spip_blocks DROP INDEX id_blocktype'], + ['maj_tables', ['spip_blocks']], + ['blocks_update_2_0_0'], + ]; + include_spip('base/upgrade'); maj_plugin($nom_meta_base_version, $version_cible, $maj); } @@ -75,50 +81,12 @@ function blocks_vider_tables($nom_meta_base_version) { } function blocks_installe_config() { - include_spip('blocks_fonctions'); - - // associer par défaut aux articles + // associer par défaut les blocks aux articles ecrire_config('blocks/objets', [ 0 => 'spip_articles', ], ); - - // un type de block de démo : titre + texte - sql_insertq( - 'spip_blocktypes', - [ - 'titre' => 'Démo texte simple', - 'identifiant' => 'demo_simple', - 'saisies' => blocks_serialize([ - [ - 'options' => - [ - 'nom' => 'titre', - 'label' => 'Titre', - 'conteneur_class' => 'pleine_largeur', - 'obligatoire' => 'oui', - ], - 'identifiant' => uniqid('@'), - 'saisie' => 'input', - ], - [ - 'options' => - [ - 'nom' => 'texte', - 'label' => 'Texte', - 'conteneur_class' => 'pleine_largeur', - 'rows' => '10', - 'inserer_barre' => 'edition', - 'previsualisation' => 'on', - ], - 'identifiant' => uniqid('@'), - 'saisie' => 'textarea', - ], - ]), - ] - ); - } function blocks_update_1_0_1() { @@ -148,3 +116,19 @@ function blocks_update_1_3_0() { ); } } + +function blocks_update_2_0_0() { + // on modifie id_blocktype en renseignant directement l'identifiant du blocktype + $blocktypes = sql_allfetsel('id_blocktype, identifiant', 'spip_blocktypes'); + foreach ($blocktypes as $blocktype) { + sql_updateq( + 'spip_blocks', + [ + 'blocktype' => $blocktype['identifiant'], + ], + 'id_blocktype = ' . $blocktype['id_blocktype'] + ); + } + // on n'a plus besoin de cette colonne + sql_alter('TABLE spip_blocks DROP id_blocktype'); +} diff --git a/formulaires/exporter_blocktypes.html b/formulaires/exporter_blocktypes.html new file mode 100644 index 0000000..ccbdef4 --- /dev/null +++ b/formulaires/exporter_blocktypes.html @@ -0,0 +1,30 @@ +<div id="formulaire_#FORM" class='formulaire_spip formulaire_#FORM'> + [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV**{message_ok})</p>] + [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>] + + <form method="post" action="#ENV{action}#formulaire_#FORM"> + <div> + #ACTION_FORMULAIRE{#ENV{action}} + + <div class="editer-groupe"> + + <div class="editer pleine_largeur"> + <div class="explication"> + <p>Les types de blocks seront exportes en YAML dans le répertoire spécifié</p> + <p>Précisez le chemin relatif à l'espace privé, à priori celui qui contient déjà + vos squelettes de blocks (ex: ../plugins/mon_plugin/squelettes/blocks)</p> + </div> + </div> + + [(#SAISIE{input, chemin, label=Chemin pour l'export des fichiers})] + + </div> + + <p class="boutons"> + <button type="submit" class="submit">Générer les fichiers YAML</button> + </p> + + </div> + </form> + +</div> diff --git a/formulaires/exporter_blocktypes.php b/formulaires/exporter_blocktypes.php new file mode 100644 index 0000000..c0168da --- /dev/null +++ b/formulaires/exporter_blocktypes.php @@ -0,0 +1,111 @@ +<?php + +if (!defined('_ECRIRE_INC_VERSION')) { + return; +} + +function formulaires_exporter_blocktypes_charger() { + if (!autoriser('webmestre')) { + return null; + } + + return ['chemin' => '']; +} + +function formulaires_exporter_blocktypes_verifier() { + $erreurs = []; + $chemin = _request('chemin'); + if (!$chemin) { + $erreurs['chemin'] = _T('info_obligatoire'); + } + if (!is_dir($chemin)) { + $erreurs['chemin'] = 'Le chemin n\'existe pas'; + } else if (!is_writable($chemin)) { + $erreurs['chemin'] = 'Le chemin n\'est pas autorisé en écriture'; + } + + return $erreurs; +} + +function formulaires_exporter_blocktypes_traiter() { + $retour = []; + $chemin = _request('chemin'); + + if ($chemin && autoriser('webmestre')) { + $chemin = rtrim($chemin, '/') . '/'; + + include_spip('inc/yaml'); + include_spip('blocks_fonctions'); + + $blocks = sql_allfetsel('*', 'spip_blocktypes'); + foreach ($blocks as $block) { + + $block['enfants'] = array_column(sql_allfetsel( + 'b.identifiant', + 'spip_blocktypes_liens bl join spip_blocktypes b on(b.id_blocktype = bl.id_objet)', + [ + 'bl.objet="blocktype"', + 'bl.role="enfant"', + 'bl.id_blocktype=' . $block['id_blocktype'], + ] + ), 'identifiant'); + + $block['parents'] = array_column(sql_allfetsel( + 'b.identifiant', + 'spip_blocktypes_liens bl join spip_blocktypes b on(b.id_blocktype = bl.id_objet)', + [ + 'bl.objet="blocktype"', + 'bl.role="parent"', + 'bl.id_blocktype=' . $block['id_blocktype'], + ] + ), 'identifiant'); + + $data = [ + 'identifiant' => $block['identifiant'], + 'titre' => $block['titre'], + 'description' => $block['description'], + ]; + if ($block['objets']) { + $data['objets'] = $block['objets']; + } + if ($block['enfants']) { + $data['enfants'] = $block['enfants']; + } + if ($block['parents']) { + $data['parents'] = $block['parents']; + } + + if ($saisies = blocks_deserialize($block['saisies'])) { + // nettoyage des saisies + $data['saisies'] = array_filter($saisies); + foreach ($data['saisies'] as $key => $saisie) { + if (empty($saisie['verifier'])) { + unset($saisie['verifier']); + } + if (($saisie['options']['autocomplete'] ?? '') === 'defaut') { + unset($saisie['options']['autocomplete']); + } + if ((string)($saisie['options']['size'] ?? '') === '40') { + unset($saisie['options']['size']); + } + unset($saisie['identifiant']); + $data['saisies'][$key] = array_filter($saisie); + } + } + + // export en yaml + $yaml = yaml_encode($data, ['inline' => 6]); + if (ecrire_fichier($chemin . $block['identifiant'] . '.yaml', $yaml)) { + $retour['message_ok'][] = 'Fichier généré : ' . $chemin . $block['identifiant'] . '.yaml'; + } else { + $retour['message_erreur'][] = 'Erreur écriture fichier : ' . $chemin . $block['identifiant'] . '.yaml'; + } + + } + + $retour['message_ok'] = join('<br>', $retour['message_ok'] ?? []); + $retour['message_erreur'] = join('<br>', $retour['message_erreur'] ?? []); + + } + return $retour; +} diff --git a/formulaires/supprimer_blocktypes.html b/formulaires/supprimer_blocktypes.html new file mode 100644 index 0000000..178fede --- /dev/null +++ b/formulaires/supprimer_blocktypes.html @@ -0,0 +1,26 @@ +<div id="formulaire_#FORM" class='formulaire_spip formulaire_#FORM'> + [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV**{message_ok})</p>] + [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>] + + <form method="post" action="#ENV{action}#formulaire_#FORM"> + <div> + #ACTION_FORMULAIRE{#ENV{action}} + + <div class="editer-groupe"> + + <div class="editer pleine_largeur"> + <div class="explication"> + <p>Une fois les blocktypes exportés en YAML, vous pouvez supprimer les tables <em>spip_blocktypes</em> et <em>spip_blocktypes_liens</em></p> + </div> + </div> + + </div> + + <p class="boutons"> + <button type="submit" class="submit">Supprimer les tables</button> + </p> + + </div> + </form> + +</div> diff --git a/formulaires/supprimer_blocktypes.php b/formulaires/supprimer_blocktypes.php new file mode 100644 index 0000000..cc15b4f --- /dev/null +++ b/formulaires/supprimer_blocktypes.php @@ -0,0 +1,26 @@ +<?php + +if (!defined('_ECRIRE_INC_VERSION')) { + return; +} + +function formulaires_supprimer_blocktypes_charger() { + if (!autoriser('webmestre')) { + return null; + } + + return []; +} + +function formulaires_supprimer_blocktypes_traiter() { + if ( + sql_drop_table('spip_blocktypes') + && sql_drop_table('spip_blocktypes_liens') + ) { + $retour['message_ok'] = 'Tables supprimées'; + } else { + $retour['message_erreur'] = 'Erreur de suppression'; + } + + return $retour; +} diff --git a/paquet.xml b/paquet.xml index 1785c5f..6980bba 100644 --- a/paquet.xml +++ b/paquet.xml @@ -1,11 +1,11 @@ <paquet prefix="blocks" - version="1.0.0" + version="2.0.0" etat="dev" compatibilite="[4.2.0;4.2.*]" logo="prive/themes/spip/images/blocks-xx.svg" documentation="" - schema="1.3.0" + schema="2.0.0" > <nom>Blocks</nom> diff --git a/prive/squelettes/contenu/update_blocks2.html b/prive/squelettes/contenu/update_blocks2.html new file mode 100644 index 0000000..ac3714e --- /dev/null +++ b/prive/squelettes/contenu/update_blocks2.html @@ -0,0 +1,13 @@ +[(#AUTORISER{webmestre}|sinon_interdire_acces)] + +<h1 class="grostitre">Mise à jour du plugin Blocsk en version 2</h1> + +<div class="ajax"> + <h2>1 - Exporter les blocktypes en YAML</h2> + #FORMULAIRE_EXPORTER_BLOCKTYPES +</div> + +<div class="ajax"> + <h2>2 - Supprimer les tables des blocktypes</h2> + #FORMULAIRE_SUPPRIMER_BLOCKTYPES +</div> -- GitLab