2.3. Fusion de tous les .docx
La fusion des documents DOCX dans le contexte de notre module de génération de guides de recherche est une opération complexe, nécessitant une série d'étapes programmées pour intégrer plusieurs documents en un seul fichier final. Cette opération est réalisée en utilisant JavaScript côté client pour orchestrer le processus et du code PHP côté serveur pour exécuter la fusion des fichiers. Voici une explication détaillée du processus :
Processus en JavaScript
/templates/page-guide-recherche.twig
// Fin de boucle ______________________________________________________________
queue.then(() => {
console.log('Lancement de la fusion des sous-documents');
$.ajax({
type: 'POST',
dataType: "json",
url: "/wp-admin/admin-ajax.php",
data: {
action: 'SID_guide_fusion_des_docx',
isIntroduction: isIntroduction,
isSommaire: isSommaire,
isAnnexes: isAnnexes,
},
success: function(response) {
if (response.url) {
window.location.href = response.url; // Déclenche le téléchargement
} else {
console.error("Erreur : URL du fichier fusionné non fournie");
}
console.error(response.message);
},
error: function(error) {
console.error('Erreur lors de la fusion', error);
}
});
}).catch((error) => {
console.error('Erreur dans le traitement des posts:', error);
});
a) Initialisation de la fusion :
- Après la création de tous les sous-documents par service propriétaire, un appel AJAX est lancé pour déclencher la fusion de ces sous-documents en un document final.
- La fonction queue.then() garantit que cet appel ne se produit qu'après l'achèvement de toutes les opérations précédentes.
b) Appel AJAX pour la fusion :
- L'appel AJAX utilise l'action
SID_guide_fusion_des_docx
, passant des paramètres pour indiquer si des sections spécifiques comme l'introduction, le sommaire, ou les annexes doivent être incluses dans le document final. - En cas de succès, le navigateur est redirigé vers l'URL du document fusionné pour déclencher le téléchargement.
Processus en PHP
Nous allons ici détailler le fonctionnement de la fonction SID_guide_fusion_des_docx()
définie dans le fichier /inc/guideRecherche/v2-guide.php
.
a) Réception de la demande de fusion :
- La fonction
add_action('wp_ajax_...')
capte l'appel AJAX initié par le JavaScript./inc/guideRecherche/v2-guide.phpuse \PhpOffice\PhpWord\PhpWord;
use \PhpOffice\PhpWord\IOFactory;
add_action('wp_ajax_SID_guide_fusion_des_docx', 'SID_guide_fusion_des_docx');
function SID_guide_fusion_des_docx(){
b) Création du document final :
- Un nouvel objet
PhpWord
est créé, configuré avec les styles nécessaires pour les titres et les liens. Une section contenant le contenu est égallement créée :/inc/guideRecherche/v2-guide.php// Créer un nouvel objet document Word -----------------------------------------------
$phpWord = new PhpWord();
// Init styles -----------------------------------------------------------------------
$linkStyle = [
'bold' => true,
'allCaps' => true,
'underline' => 'single',
'color' => '000000',
];
$phpWord->addTitleStyle(
1,
[
'bold' => true,
'color' => '8C4A8E',
'size' => 13
],
[
'align' => 'center',
'spaceBefore' => 0,
'spaceAfter' => 600,
]
);
$phpWord->addTitleStyle(2,[
'bold' => true,
'color' => '965592',
]);
$phpWord->addTitleStyle(3,[
'bold' => true,
'color' => 'CA438F',
]);
$tocStyle = array(
'tabLeader' => \PhpOffice\PhpWord\Style\TOC::TAB_LEADER_DOT,
'tabPos' => 9000, // Position de l'onglet pour le numéro de page
'indent' => 230, // Indentation des titres
);
// Ajouter une section au document ---------------------------------------------------
$section = $phpWord->addSection();
c) Pages optionnelles :
- L'utilisateur peu choisir d'ajouter des sections (introduction, sommaire, annexes etc). Si demandé, le script peu appeler des sous-fonctions PHP associées
docxAddPageDeGarde()
,docxIntroduction()
,docxAddSommaire()
.../inc/guideRecherche/v2-guide.php// PAGE DE GARDE + INTRO ----------------------------------------------------------------
if (isset($_POST['isIntroduction']) && $_POST['isIntroduction'] == 'true') {
docxAddPageDeGarde($section);
docxIntroduction($section);
}
// SOMMAIRE, table des matieres ---------------------------------------------------------
if (isset($_POST['isSommaire']) && $_POST['isSommaire'] == 'true') {
docxAddSommaire($section, $tocStyle);
}
d) Parcours des sous-documents :
- Le script parcourt le répertoire contenant les sous-documents (
.docx
) créés préalablement, les ouvre et les charge un par un :/inc/guideRecherche/v2-guide.php// Répértoire des fichiers ----------------------------------------------------------------------------
$upload_dir = wp_upload_dir();
$basePath = $upload_dir['basedir'] . '/guide-de-recherche/';
$baseUrl = $upload_dir['baseurl'] . '/guide-de-recherche/';
// Get files / content --------------------------------------------------------------------------------
$partIndex = 1;
while (true) {
// Init
$partFile = $basePath . "guide_de_recherche_part_" . $partIndex . ".docx";
$partIndex ++;
// Check if file exist
if (!file_exists($partFile)) {
break;
}
$doc = IOFactory::load($partFile);
e) Parcours des sous-documents :
- Le script commence par parcourir chaque section d'un document source chargé précédemment(
$doc
), ce qui est fait parforeach ($doc->getSections() as $section)
. Pour chaque section trouvée, une nouvelle section ($newSection
) est créée dans le document de destination ($phpWord
). - À l'intérieur de chaque section, le script parcourt ensuite tous les éléments (
$element
) qu'elle contient viaforeach ($section->getElements() as $element)
- Lorsqu'un élément de type
TextRun
est trouvé (un ensemble de textes avec un style commun), le script crée unTextRun
correspondant dans la nouvelle section. Le style de paragraphe de l'élément original est conservé. - Pour chaque élément textuel (
Text
) à l'intérieur duTextRun
, le script vérifie si le texte correspond à un format spécifique indiquant un lien (\[URL: (.*?) \| (.*?)\]
). Si c'est le cas, il extrait l'URL et le texte du lien, puis crée un lien dans le nouveau document en utilisant ces informations. Si le texte n'indique pas un lien, il est simplement ajouté tel quel. - Si un élément
TextBreak
(saut de ligne) est rencontré, un saut de ligne est ajouté à l'endroit correspondant dans la nouvelle section. - Pour les éléments de type
Title
(titre), le script ajoute un titre dans la nouvelle section en conservant le texte et la profondeur (niveau) du titre original./inc/guideRecherche/v2-guide.phpforeach ($doc->getSections() as $section) {
$newSection = $phpWord->addSection();
foreach ($section->getElements() as $element) {
// Ensemble d'elements
if ($element instanceof \PhpOffice\PhpWord\Element\TextRun) {
$newElement = $newSection->addTextRun($element->getParagraphStyle());
foreach ($element->getElements() as $textElement) {
if ($textElement instanceof \PhpOffice\PhpWord\Element\Text) {
// Traitez ce texte comme un lien
if( preg_match('/\[URL: (.*?) \| (.*?)\]/', $textElement->getText(), $matches) ){
$url = $matches[1]; // L'URL
$linkText = $matches[2]; // Le texte du lien
$newElement->addLink( $url , $linkText, $linkStyle);
}
else {
$newElement->addText($textElement->getText(), $textElement->getFontStyle());
}
}
elseif ($textElement instanceof \PhpOffice\PhpWord\Element\TextBreak) {
$newElement->addTextBreak();
}
}
}
// Titres
elseif ($element instanceof \PhpOffice\PhpWord\Element\Title) {
$newSection->addTitle($element->getText(), $element->getDepth());
}
// Textes
elseif ($element instanceof \PhpOffice\PhpWord\Element\Text) {
$newSection->addText($element->getText(), $element->getFontStyle());
}
}
}
f) Pieds de page :
- Le code ci dessous ajoute le numéro de page dans le footer de celles-ci :
/inc/guideRecherche/v2-guide.php
// Ajouter le pied de page avec le numéro de page
$footer = $newSection->addFooter();
$footer->addPreserveText('{PAGE}', null, ['align' => 'right']);
g) Sauvegarde et retour :
- Lorsque tous les fichiers
.docx
sont regroupés dans un seul objet PHP, nous enregistrons ce dernier fichier sur le serveur. - L'url de ce fichier est retournée pour lancer son téléchargement en Javascript
/inc/guideRecherche/v2-guide.php
// Save file ------------------------------------------------------------------------------------
$fileName = 'guide_de_recherche_full.docx';
$finalDoc = $basePath . '/' . $fileName;
$finalDocUrl = $baseUrl . '/' . $fileName;
$objWriter = IOFactory::createWriter($phpWord, 'Word2007');
$objWriter->save($finalDoc);
// Return ---------------------------------------------------------------------------------------
echo json_encode(array(
'url' => $finalDocUrl,
'message' => 'Fin de la fusion.'
));
die;