Skip to main content

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.php
      use \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 par foreach ($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 via foreach ($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 un TextRun 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 du TextRun, 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.php
      foreach ($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;