Skip to content
Extraits de code Groupes Projets
Valider 86da5dd7 rédigé par nicod's avatar nicod
Parcourir les fichiers

feat(WIP): V2 avec rupture de compatibilité

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
parent 3974be73
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
......@@ -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)
......
......@@ -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 ?
......
......@@ -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;
}
......@@ -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');
}
<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>
<?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;
}
<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>
<?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;
}
<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>
......
[(#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>
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter