452 lines
25 KiB
PHP
452 lines
25 KiB
PHP
<?php
|
||
declare(strict_types=1);
|
||
|
||
/**
|
||
* Export Word (.docx) du CV au format Europass.
|
||
* Même principe que ExportWord : le fichier OOXML est écrit à la main avec ZipArchive.
|
||
* Reçoit le contenu préparé par donnees_europass(), comme l'aperçu HTML.
|
||
*
|
||
* Police : Arial dans Word (Open Sans n'est pas installée partout) ; l'aperçu et le PDF utilisent Open Sans.
|
||
* Unités : twips (1 mm = 56,7), demi-points pour les corps, huitièmes de point pour les filets.
|
||
*/
|
||
final class ExportEuropass
|
||
{
|
||
private const BLEU = '004B80';
|
||
private const BLEU_CLAIR = '4D9ACB';
|
||
private const FILET = 'C0DBED';
|
||
private const FOND_LIGNE = 'F2F8FC';
|
||
private const TEXTE = '1A1A1A';
|
||
private const GRIS = '404040';
|
||
private const GRIS_CLAIR = '6F6F6F';
|
||
|
||
private const PAGE_L = 11906;
|
||
private const PAGE_H = 16838;
|
||
private const MARGE = 794; // 14 mm
|
||
private const TEXTE_L = self::PAGE_L - 2 * self::MARGE;
|
||
|
||
private const NS = 'xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" '
|
||
. 'xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" '
|
||
. 'xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" '
|
||
. 'xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" '
|
||
. 'xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"';
|
||
|
||
/**
|
||
* @param array $d contenu renvoyé par donnees_europass()
|
||
* @param string $logo chemin du logo Europass blanc (PNG transparent)
|
||
* @param ?string $photo chemin de la photo JPEG, ou null
|
||
*/
|
||
public static function generer(array $d, string $logo, ?string $photo = null): string
|
||
{
|
||
$tmp = tempnam(sys_get_temp_dir(), 'europass');
|
||
$zip = new ZipArchive();
|
||
if ($tmp === false || $zip->open($tmp, ZipArchive::OVERWRITE) !== true) {
|
||
throw new RuntimeException(t('Le fichier Word n\'a pas pu être créé.'));
|
||
}
|
||
$avecPhoto = $photo !== null && is_file($photo);
|
||
$zip->addFromString('[Content_Types].xml', self::types());
|
||
$zip->addFromString('_rels/.rels', self::relsRacine());
|
||
$zip->addFromString('docProps/core.xml', self::proprietes($d));
|
||
$zip->addFromString('word/document.xml', self::document($d));
|
||
$zip->addFromString('word/header1.xml', self::entete($d, $logo, $avecPhoto ? $photo : null));
|
||
$zip->addFromString('word/header2.xml', '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><w:hdr ' . self::NS . '>' . self::p('') . '</w:hdr>');
|
||
$zip->addFromString('word/_rels/header1.xml.rels', self::relsEntete($avecPhoto));
|
||
$zip->addFromString('word/styles.xml', self::styles(['fr' => 'fr-FR', 'en' => 'en-GB', 'de' => 'de-DE'][$d['langue']] ?? 'fr-FR'));
|
||
$zip->addFromString('word/settings.xml', self::reglages());
|
||
$zip->addFromString('word/footer1.xml', self::pied());
|
||
$zip->addFromString('word/_rels/document.xml.rels', self::relsDocument());
|
||
$zip->addFromString('word/media/logo.png', (string) file_get_contents($logo));
|
||
if ($avecPhoto) {
|
||
$zip->addFromString('word/media/photo.jpg', (string) file_get_contents($photo));
|
||
}
|
||
$zip->close();
|
||
$contenu = (string) file_get_contents($tmp);
|
||
unlink($tmp);
|
||
return $contenu;
|
||
}
|
||
|
||
// -----------------------------------------------------------------------
|
||
// Briques
|
||
// -----------------------------------------------------------------------
|
||
|
||
private static function x(string $texte): string
|
||
{
|
||
$texte = preg_replace('/[^\x{9}\x{A}\x{D}\x{20}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]/u', '', $texte) ?? '';
|
||
return htmlspecialchars($texte, ENT_XML1 | ENT_QUOTES, 'UTF-8');
|
||
}
|
||
|
||
/** Options : b, i, caps, color, sz (demi-points). */
|
||
private static function r(string $texte, array $o = []): string
|
||
{
|
||
$p = '';
|
||
if (!empty($o['b'])) { $p .= '<w:b/>'; }
|
||
if (!empty($o['i'])) { $p .= '<w:i/>'; }
|
||
if (!empty($o['caps'])) { $p .= '<w:caps/>'; }
|
||
if (isset($o['color'])) { $p .= '<w:color w:val="' . $o['color'] . '"/>'; }
|
||
if (isset($o['sz'])) { $p .= '<w:sz w:val="' . $o['sz'] . '"/><w:szCs w:val="' . $o['sz'] . '"/>'; }
|
||
return '<w:r>' . ($p !== '' ? '<w:rPr>' . $p . '</w:rPr>' : '') . '<w:t xml:space="preserve">' . self::x($texte) . '</w:t></w:r>';
|
||
}
|
||
|
||
/** Options : style, avant, apres, keepNext, retrait (gauche), suspendu, jc, bordureBas [taille, couleur]. */
|
||
private static function p(string $runs, array $o = []): string
|
||
{
|
||
$p = '';
|
||
if (isset($o['style'])) { $p .= '<w:pStyle w:val="' . $o['style'] . '"/>'; }
|
||
if (!empty($o['keepNext'])) { $p .= '<w:keepNext/>'; }
|
||
if (isset($o['bordureBas'])) {
|
||
$p .= '<w:pBdr><w:bottom w:val="single" w:sz="' . $o['bordureBas'][0] . '" w:space="4" w:color="' . $o['bordureBas'][1] . '"/></w:pBdr>';
|
||
}
|
||
if (isset($o['avant']) || isset($o['apres'])) {
|
||
$p .= '<w:spacing' . (isset($o['avant']) ? ' w:before="' . $o['avant'] . '"' : '') . (isset($o['apres']) ? ' w:after="' . $o['apres'] . '"' : '') . '/>';
|
||
}
|
||
if (isset($o['retrait'])) {
|
||
$p .= '<w:ind w:left="' . $o['retrait'] . '"' . (isset($o['suspendu']) ? ' w:hanging="' . $o['suspendu'] . '"' : '') . '/>';
|
||
}
|
||
if (isset($o['jc'])) { $p .= '<w:jc w:val="' . $o['jc'] . '"/>'; }
|
||
return '<w:p>' . ($p !== '' ? '<w:pPr>' . $p . '</w:pPr>' : '') . $runs . '</w:p>';
|
||
}
|
||
|
||
private static function tc(int $largeur, string $contenu, array $o = []): string
|
||
{
|
||
$p = '<w:tcW w:w="' . $largeur . '" w:type="dxa"/>';
|
||
if (isset($o['span'])) { $p .= '<w:gridSpan w:val="' . $o['span'] . '"/>'; }
|
||
if (isset($o['bordures'])) { $p .= '<w:tcBorders>' . $o['bordures'] . '</w:tcBorders>'; }
|
||
if (isset($o['fond'])) { $p .= '<w:shd w:val="clear" w:color="auto" w:fill="' . $o['fond'] . '"/>'; }
|
||
if (isset($o['marges'])) {
|
||
[$h, $dr, $b, $g] = $o['marges'];
|
||
$p .= '<w:tcMar><w:top w:w="' . $h . '" w:type="dxa"/><w:left w:w="' . $g . '" w:type="dxa"/>'
|
||
. '<w:bottom w:w="' . $b . '" w:type="dxa"/><w:right w:w="' . $dr . '" w:type="dxa"/></w:tcMar>';
|
||
}
|
||
$p .= '<w:vAlign w:val="' . ($o['vAlign'] ?? 'top') . '"/>';
|
||
return '<w:tc><w:tcPr>' . $p . '</w:tcPr>' . $contenu . '</w:tc>';
|
||
}
|
||
|
||
private static function tbl(array $colonnes, string $lignes, int $retrait = 0): string
|
||
{
|
||
$grille = '';
|
||
foreach ($colonnes as $l) {
|
||
$grille .= '<w:gridCol w:w="' . $l . '"/>';
|
||
}
|
||
return '<w:tbl><w:tblPr><w:tblW w:w="' . array_sum($colonnes) . '" w:type="dxa"/>'
|
||
. '<w:tblInd w:w="' . $retrait . '" w:type="dxa"/><w:tblLayout w:type="fixed"/>'
|
||
. '<w:tblCellMar><w:left w:w="0" w:type="dxa"/><w:right w:w="0" w:type="dxa"/></w:tblCellMar></w:tblPr>'
|
||
. '<w:tblGrid>' . $grille . '</w:tblGrid>' . $lignes . '</w:tbl>';
|
||
}
|
||
|
||
private static function filet(string $cote, int $taille, string $couleur): string
|
||
{
|
||
return '<w:' . $cote . ' w:val="single" w:sz="' . $taille . '" w:space="0" w:color="' . $couleur . '"/>';
|
||
}
|
||
|
||
/** Image en ligne. $l et $h en mm. */
|
||
private static function image(string $rid, int $id, string $nom, float $l, float $h): string
|
||
{
|
||
$cx = (int) round($l * 36000);
|
||
$cy = (int) round($h * 36000);
|
||
return '<w:r><w:drawing><wp:inline distT="0" distB="0" distL="0" distR="0">'
|
||
. '<wp:extent cx="' . $cx . '" cy="' . $cy . '"/><wp:docPr id="' . $id . '" name="' . $nom . '" descr="' . $nom . '"/>'
|
||
. '<a:graphic><a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:pic>'
|
||
. '<pic:nvPicPr><pic:cNvPr id="' . $id . '" name="' . $nom . '"/><pic:cNvPicPr/></pic:nvPicPr>'
|
||
. '<pic:blipFill><a:blip r:embed="' . $rid . '"/><a:stretch><a:fillRect/></a:stretch></pic:blipFill>'
|
||
. '<pic:spPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="' . $cx . '" cy="' . $cy . '"/></a:xfrm>'
|
||
. '<a:prstGeom prst="rect"><a:avLst/></a:prstGeom></pic:spPr>'
|
||
. '</pic:pic></a:graphicData></a:graphic></wp:inline></w:drawing></w:r>';
|
||
}
|
||
|
||
private static function titre(string $texte): string
|
||
{
|
||
return self::p(self::r('● ', ['color' => self::BLEU_CLAIR, 'sz' => 16]) . self::r($texte), ['style' => 'TitreEuropass']);
|
||
}
|
||
|
||
// -----------------------------------------------------------------------
|
||
// Document
|
||
// -----------------------------------------------------------------------
|
||
|
||
private static function document(array $d): string
|
||
{
|
||
$L = $d['libelles'];
|
||
$corps = '';
|
||
|
||
if ($d['resume']) {
|
||
$corps .= self::titre($L['apropos']);
|
||
foreach ($d['resume'] as $l) {
|
||
$corps .= self::p(self::r($l));
|
||
}
|
||
}
|
||
|
||
if ($d['formations']) {
|
||
$corps .= self::titre($L['formation']);
|
||
foreach ($d['formations'] as $i => $f) {
|
||
$dernier = $i === count($d['formations']) - 1;
|
||
if (trim($f['dates'] . $f['lieu']) !== '') {
|
||
$corps .= self::p(self::r(trim($f['dates'] . ' ' . $f['lieu']), ['color' => self::GRIS_CLAIR, 'sz' => 17]), ['apres' => 20, 'keepNext' => true]);
|
||
}
|
||
$corps .= self::p(
|
||
self::r($f['diplome'], ['b' => true, 'color' => self::GRIS, 'sz' => 20])
|
||
. ($f['etablissement'] !== '' ? self::r(' ' . $f['etablissement'], ['color' => self::GRIS, 'sz' => 20]) : ''),
|
||
['apres' => 120] + ($dernier ? [] : ['bordureBas' => [4, self::FILET]])
|
||
);
|
||
}
|
||
}
|
||
|
||
if ($d['experiences']) {
|
||
$corps .= self::titre($L['experience']);
|
||
foreach ($d['experiences'] as $i => $x) {
|
||
$dernier = $i === count($d['experiences']) - 1;
|
||
if ($x['employeur'] !== '' || $x['lieu'] !== '') {
|
||
$corps .= self::p(
|
||
self::r($x['employeur'], ['b' => true]) . ($x['employeur'] !== '' && $x['lieu'] !== '' ? self::r(' – ') : '') . self::r($x['lieu']),
|
||
['apres' => 20, 'keepNext' => true]
|
||
);
|
||
}
|
||
$corps .= self::p(
|
||
self::r($x['poste'], ['b' => true, 'color' => self::GRIS, 'sz' => 20]) . self::r(' – ' . $x['dates'], ['color' => self::BLEU, 'sz' => 20]),
|
||
['apres' => 40, 'keepNext' => true]
|
||
);
|
||
foreach ($x['details'] as [$libelle, $valeur]) {
|
||
$corps .= self::p(self::r($libelle . $d['deux_points'] . ' ', ['b' => true]) . self::r($valeur), ['apres' => 20]);
|
||
}
|
||
if ($x['realisations']) {
|
||
$corps .= self::p(self::r($L['realisations'], ['b' => true]), ['avant' => 40, 'apres' => 20, 'keepNext' => true]);
|
||
foreach ($x['realisations'] as $r) {
|
||
$corps .= self::p(self::r('•') . '<w:r><w:tab/></w:r>' . self::r($r), ['retrait' => 600, 'suspendu' => 240, 'apres' => 10]);
|
||
}
|
||
}
|
||
$corps .= self::p('', ['apres' => 100] + ($dernier ? [] : ['bordureBas' => [4, self::FILET]]));
|
||
}
|
||
}
|
||
|
||
if ($d['maternelles'] || $d['autres']) {
|
||
$corps .= self::titre($L['langues']);
|
||
if ($d['maternelles']) {
|
||
$corps .= self::p(self::r($L['maternelles'] . ' ') . self::r(implode(' | ', $d['maternelles']), ['b' => true]));
|
||
}
|
||
if ($d['autres']) {
|
||
$corps .= self::p(self::r($L['autres']), ['avant' => 60]);
|
||
$corps .= $d['avec_grille'] ? self::grille($d) : self::p(implode(self::r(' '), array_map(
|
||
static fn ($l) => self::r($l['langue'], ['b' => true]) . ($l['niveau'] !== '' ? self::r($d['deux_points'] . ' ' . $l['niveau']) : ''),
|
||
$d['autres']
|
||
)));
|
||
$corps .= self::p(self::r($L['niveaux'], ['i' => true, 'color' => self::GRIS_CLAIR, 'sz' => 16]), ['avant' => 40]);
|
||
}
|
||
}
|
||
|
||
if ($d['competences']) {
|
||
$corps .= self::titre($L['competences']);
|
||
foreach ($d['competences'] as $groupe => $liste) {
|
||
$corps .= self::p(self::r($groupe, ['b' => true, 'color' => self::GRIS_CLAIR]), ['avant' => 80, 'apres' => 20, 'keepNext' => true]);
|
||
$corps .= self::p(self::r(implode(' | ', $liste)));
|
||
}
|
||
}
|
||
|
||
if ($d['benevolat']) {
|
||
$corps .= self::titre($L['benevolat']);
|
||
foreach ($d['benevolat'] as $b) {
|
||
$corps .= self::p(self::r($b, ['b' => true]));
|
||
}
|
||
}
|
||
|
||
if ($d['permis']) {
|
||
$corps .= self::titre($L['permis']);
|
||
foreach ($d['permis'] as $p) {
|
||
$corps .= self::p(self::r($L['permis_ligne'] . ' ', ['b' => true]) . self::r($p));
|
||
}
|
||
}
|
||
|
||
// Première page : le bandeau est dans son en-tête ; les pages suivantes ont un en-tête vide et une marge haute
|
||
$section = '<w:sectPr>'
|
||
. '<w:headerReference w:type="first" r:id="rId4"/><w:headerReference w:type="default" r:id="rId5"/>'
|
||
. '<w:footerReference w:type="default" r:id="rId3"/><w:footerReference w:type="first" r:id="rId3"/>'
|
||
. '<w:pgSz w:w="' . self::PAGE_L . '" w:h="' . self::PAGE_H . '"/>'
|
||
. '<w:pgMar w:top="850" w:right="' . self::MARGE . '" w:bottom="850" w:left="' . self::MARGE . '" w:header="0" w:footer="340" w:gutter="0"/>'
|
||
. '<w:titlePg/>'
|
||
. '</w:sectPr>';
|
||
|
||
return '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
|
||
. '<w:document ' . self::NS . '><w:body>' . $corps . $section . '</w:body></w:document>';
|
||
}
|
||
|
||
/** En-tête de la première page : bandeau bleu de bord à bord, avec photo, nom, titre, coordonnées et logo. */
|
||
private static function entete(array $d, string $logo, ?string $photo): string
|
||
{
|
||
$bleu = ['fond' => self::BLEU];
|
||
[$lpx, $hpx] = getimagesize($logo) ?: [700, 142];
|
||
$logoL = 34.0;
|
||
$logoH = round($logoL * $hpx / $lpx, 1);
|
||
$lLogo = 2400;
|
||
$lPhoto = $photo ? 2000 : 0;
|
||
$lTexte = self::PAGE_L - 2 * self::MARGE - $lLogo - $lPhoto;
|
||
|
||
$identite = self::p(self::r($d['nom'], ['b' => true, 'color' => 'FFFFFF', 'sz' => 34]), ['apres' => 20]);
|
||
if ($d['titre'] !== '') {
|
||
$identite .= self::p(self::r($d['titre'], ['color' => 'DBE9F4', 'sz' => 21]), ['apres' => 60]);
|
||
}
|
||
if ($d['coordonnees']) {
|
||
$runs = '';
|
||
foreach ($d['coordonnees'] as $i => $k) {
|
||
$runs .= ($i ? self::r(' | ', ['color' => '6E95B8', 'sz' => 17]) : '')
|
||
. self::r($k['libelle'] . $d['deux_points'] . ' ', ['b' => true, 'color' => 'FFFFFF', 'sz' => 17])
|
||
. self::r($k['valeur'], ['color' => 'FFFFFF', 'sz' => 17]);
|
||
}
|
||
$identite .= self::p($runs, ['apres' => 0]);
|
||
}
|
||
|
||
$vide = self::p('', ['apres' => 0]);
|
||
$cellules = self::tc(self::MARGE, $vide, $bleu);
|
||
if ($photo) {
|
||
$cellules .= self::tc($lPhoto, self::p(self::image('rId2', 2, 'Photo', 28, 28), ['apres' => 0]), $bleu + ['vAlign' => 'center']);
|
||
}
|
||
$cellules .= self::tc($lTexte, $identite, $bleu + ['vAlign' => 'center', 'marges' => [0, 200, 0, 0]])
|
||
. self::tc($lLogo, self::p(self::image('rId1', 1, 'europass', $logoL, $logoH), ['apres' => 0, 'jc' => 'right']), $bleu + ['vAlign' => 'top'])
|
||
. self::tc(self::MARGE, $vide, $bleu);
|
||
$colonnes = array_values(array_filter([self::MARGE, $lPhoto, $lTexte, $lLogo, self::MARGE]));
|
||
$lignes = '<w:tr><w:trPr><w:trHeight w:val="340" w:hRule="exact"/></w:trPr>' . self::tc(self::PAGE_L, $vide, $bleu + ['span' => count($colonnes)]) . '</w:tr>'
|
||
. '<w:tr>' . $cellules . '</w:tr>'
|
||
. '<w:tr><w:trPr><w:trHeight w:val="300" w:hRule="exact"/></w:trPr>' . self::tc(self::PAGE_L, $vide, $bleu + ['span' => count($colonnes)]) . '</w:tr>';
|
||
return '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><w:hdr ' . self::NS . '>'
|
||
. self::tbl($colonnes, $lignes, -self::MARGE) . self::p('', ['apres' => 0]) . '</w:hdr>';
|
||
}
|
||
|
||
/** Grille européenne des langues. */
|
||
private static function grille(array $d): string
|
||
{
|
||
$L = $d['libelles'];
|
||
$lLangue = 1900;
|
||
$lCase = intdiv(self::TEXTE_L - $lLangue, 5);
|
||
$colonnes = [$lLangue, $lCase, $lCase, $lCase, $lCase, $lCase];
|
||
$centre = static fn (string $runs): string => self::p($runs, ['jc' => 'center', 'apres' => 0]);
|
||
$haut = self::filet('top', 6, self::BLEU_CLAIR);
|
||
$bas = self::filet('bottom', 6, self::BLEU_CLAIR);
|
||
$marges = ['marges' => [60, 40, 60, 40]];
|
||
|
||
$lignes = '<w:tr>' . self::tc($lLangue, self::p(''), $marges)
|
||
. self::tc(2 * $lCase, $centre(self::r(mb_strtoupper($L['comprehension']), ['b' => true, 'sz' => 17])), $marges + ['span' => 2, 'bordures' => $bas])
|
||
. self::tc(2 * $lCase, $centre(self::r(mb_strtoupper($L['expression']), ['b' => true, 'sz' => 17])), $marges + ['span' => 2, 'bordures' => $bas])
|
||
. self::tc($lCase, $centre(self::r(mb_strtoupper($L['ecrit']), ['b' => true, 'sz' => 17])), $marges + ['bordures' => $bas])
|
||
. '</w:tr>';
|
||
$sous = self::tc($lLangue, self::p(''), $marges);
|
||
foreach (array_slice($L['grille'], 0, 4) as $g) {
|
||
$sous .= self::tc($lCase, $centre(self::r($g, ['sz' => 16])), $marges);
|
||
}
|
||
$lignes .= '<w:tr>' . $sous . self::tc($lCase, self::p(''), $marges) . '</w:tr>';
|
||
|
||
foreach ($d['autres'] as $i => $l) {
|
||
$fond = $i % 2 === 0 ? ['fond' => self::FOND_LIGNE] : [];
|
||
$bord = ['bordures' => $haut . ($i === count($d['autres']) - 1 ? $bas : '')];
|
||
$cellules = self::tc($lLangue, self::p(self::r($l['langue'], ['b' => true, 'sz' => 17]), ['apres' => 0]), $marges + $fond + $bord + ['vAlign' => 'center']);
|
||
if ($l['grille']) {
|
||
foreach ($l['grille'] as $niveau) {
|
||
$cellules .= self::tc($lCase, $centre(self::r($niveau ?: '–', ['sz' => 17])), $marges + $fond + $bord + ['vAlign' => 'center']);
|
||
}
|
||
} else {
|
||
$cellules .= self::tc(5 * $lCase, $centre(self::r($l['niveau'] !== '' ? $L['niveau'] . ' ' . $l['niveau'] : '–', ['sz' => 17])), $marges + $fond + $bord + ['span' => 5, 'vAlign' => 'center']);
|
||
}
|
||
$lignes .= '<w:tr><w:trPr><w:cantSplit/></w:trPr>' . $cellules . '</w:tr>';
|
||
}
|
||
return self::tbl($colonnes, $lignes);
|
||
}
|
||
|
||
private static function pied(): string
|
||
{
|
||
$petit = ['color' => self::GRIS_CLAIR, 'sz' => 14];
|
||
$champ = static fn (string $nom): string => '<w:fldSimple w:instr=" ' . $nom . ' ">' . self::r('1', $petit) . '</w:fldSimple>';
|
||
return '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
|
||
. '<w:ftr ' . self::NS . '>'
|
||
. self::p($champ('PAGE') . self::r(' / ', $petit) . $champ('NUMPAGES'), ['jc' => 'right', 'apres' => 0])
|
||
. '</w:ftr>';
|
||
}
|
||
|
||
// -----------------------------------------------------------------------
|
||
// Fichiers fixes
|
||
// -----------------------------------------------------------------------
|
||
|
||
private static function styles(string $langue): string
|
||
{
|
||
return '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
|
||
. '<w:styles xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">'
|
||
. '<w:docDefaults>'
|
||
. '<w:rPrDefault><w:rPr><w:rFonts w:ascii="Arial" w:hAnsi="Arial" w:cs="Arial" w:eastAsia="Arial"/>'
|
||
. '<w:color w:val="' . self::TEXTE . '"/><w:sz w:val="19"/><w:szCs w:val="19"/><w:lang w:val="' . $langue . '"/></w:rPr></w:rPrDefault>'
|
||
. '<w:pPrDefault><w:pPr><w:spacing w:before="0" w:after="40" w:line="264" w:lineRule="auto"/></w:pPr></w:pPrDefault>'
|
||
. '</w:docDefaults>'
|
||
. '<w:style w:type="paragraph" w:default="1" w:styleId="Normal"><w:name w:val="Normal"/><w:qFormat/></w:style>'
|
||
. '<w:style w:type="paragraph" w:styleId="TitreEuropass"><w:name w:val="heading 2"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:qFormat/>'
|
||
. '<w:pPr><w:keepNext/><w:pBdr><w:bottom w:val="single" w:sz="12" w:space="2" w:color="' . self::BLEU_CLAIR . '"/></w:pBdr>'
|
||
. '<w:spacing w:before="200" w:after="120"/><w:ind w:left="-280"/><w:outlineLvl w:val="1"/></w:pPr>'
|
||
. '<w:rPr><w:b/><w:caps/><w:sz w:val="22"/><w:szCs w:val="22"/></w:rPr></w:style>'
|
||
. '</w:styles>';
|
||
}
|
||
|
||
private static function reglages(): string
|
||
{
|
||
return '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
|
||
. '<w:settings xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">'
|
||
. '<w:defaultTabStop w:val="708"/>'
|
||
. '<w:compat><w:compatSetting w:name="compatibilityMode" w:uri="http://schemas.microsoft.com/office/word" w:val="15"/></w:compat>'
|
||
. '</w:settings>';
|
||
}
|
||
|
||
private static function types(): string
|
||
{
|
||
$wml = 'application/vnd.openxmlformats-officedocument.wordprocessingml.';
|
||
return '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
|
||
. '<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">'
|
||
. '<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>'
|
||
. '<Default Extension="xml" ContentType="application/xml"/>'
|
||
. '<Default Extension="png" ContentType="image/png"/>'
|
||
. '<Default Extension="jpg" ContentType="image/jpeg"/>'
|
||
. '<Override PartName="/word/document.xml" ContentType="' . $wml . 'document.main+xml"/>'
|
||
. '<Override PartName="/word/styles.xml" ContentType="' . $wml . 'styles+xml"/>'
|
||
. '<Override PartName="/word/settings.xml" ContentType="' . $wml . 'settings+xml"/>'
|
||
. '<Override PartName="/word/footer1.xml" ContentType="' . $wml . 'footer+xml"/>'
|
||
. '<Override PartName="/word/header1.xml" ContentType="' . $wml . 'header+xml"/>'
|
||
. '<Override PartName="/word/header2.xml" ContentType="' . $wml . 'header+xml"/>'
|
||
. '<Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/>'
|
||
. '</Types>';
|
||
}
|
||
|
||
private static function relsRacine(): string
|
||
{
|
||
return '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
|
||
. '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'
|
||
. '<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>'
|
||
. '<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>'
|
||
. '</Relationships>';
|
||
}
|
||
|
||
private static function relsDocument(): string
|
||
{
|
||
$t = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/';
|
||
return '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
|
||
. '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'
|
||
. '<Relationship Id="rId1" Type="' . $t . 'styles" Target="styles.xml"/>'
|
||
. '<Relationship Id="rId2" Type="' . $t . 'settings" Target="settings.xml"/>'
|
||
. '<Relationship Id="rId3" Type="' . $t . 'footer" Target="footer1.xml"/>'
|
||
. '<Relationship Id="rId4" Type="' . $t . 'header" Target="header1.xml"/>'
|
||
. '<Relationship Id="rId5" Type="' . $t . 'header" Target="header2.xml"/>'
|
||
. '</Relationships>';
|
||
}
|
||
|
||
private static function relsEntete(bool $photo): string
|
||
{
|
||
$t = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/';
|
||
return '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
|
||
. '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'
|
||
. '<Relationship Id="rId1" Type="' . $t . 'image" Target="media/logo.png"/>'
|
||
. ($photo ? '<Relationship Id="rId2" Type="' . $t . 'image" Target="media/photo.jpg"/>' : '')
|
||
. '</Relationships>';
|
||
}
|
||
|
||
private static function proprietes(array $d): string
|
||
{
|
||
$date = gmdate('Y-m-d\TH:i:s\Z');
|
||
return '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
|
||
. '<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" '
|
||
. 'xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" '
|
||
. 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
|
||
. '<dc:title>' . self::x($d['fichier']) . '</dc:title><dc:creator>IT Club</dc:creator>'
|
||
. '<dcterms:created xsi:type="dcterms:W3CDTF">' . $date . '</dcterms:created>'
|
||
. '<dcterms:modified xsi:type="dcterms:W3CDTF">' . $date . '</dcterms:modified>'
|
||
. '</cp:coreProperties>';
|
||
}
|
||
}
|