From 29e5e72427573090947894ac783cc8ce4aebf87f Mon Sep 17 00:00:00 2001 From: "vitaly.erofeev" Date: Mon, 1 Aug 2022 10:03:16 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20=D0=9F=D0=BE=D0=B4=D0=B4=D0=B5=D1=80?= =?UTF-8?q?=D0=B6=D0=BA=D0=B0=20=D0=BA=D0=BE=D0=BB=D0=BE=D0=BD=D1=82=D0=B8?= =?UTF-8?q?=D1=82=D1=83=D0=BB=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .phpunit.result.cache | 2 +- composer.json | 5 +- src/DocxDocument.php | 46 +++++++++++++++++ src/PhpDocxTemplate.php | 18 ++++++- tests/PhpDocxTemplateTest.php | 88 +++++++++++++++++++++++++++++++++ tests/templates/image.docx | Bin 1409666 -> 1409199 bytes tests/templates/template9.docx | Bin 0 -> 19498 bytes 7 files changed, 156 insertions(+), 3 deletions(-) create mode 100644 tests/templates/template9.docx diff --git a/.phpunit.result.cache b/.phpunit.result.cache index 70149ca..366e0d6 100644 --- a/.phpunit.result.cache +++ b/.phpunit.result.cache @@ -1 +1 @@ -{"version":1,"defects":{"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testTable":3,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testImages":3},"times":{"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testTable":0.0070000000000000001,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testXmlToString":0.0089999999999999993,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testGetDocx":0.002,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testGetXml":0.0089999999999999993,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testPatchXml":0.0030000000000000001,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testRenderXml":0.031,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testRender":0.048000000000000001,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testLineBreak":0.0030000000000000001,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testCyrillic":0.0080000000000000002,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testForLoop":0.0060000000000000001,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testImages":2.1389999999999998}} \ No newline at end of file +{"version":1,"defects":{"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testTable":3,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testImages":4,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testSections":3},"times":{"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testTable":0.008,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testXmlToString":0.005,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testGetDocx":0.002,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testGetXml":0.002,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testPatchXml":0.002,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testRenderXml":0.014,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testRender":0.007,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testLineBreak":0.003,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testCyrillic":0.002,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testForLoop":0.006,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testImages":0.788,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testSections":0.009}} \ No newline at end of file diff --git a/composer.json b/composer.json index 9806557..ea0d928 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,10 @@ "email": "bingosoft@bk.ru" }], "config": { - "vendor-dir": "./vendor" + "vendor-dir": "./vendor", + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } }, "require": { "ext-zip": "*", diff --git a/src/DocxDocument.php b/src/DocxDocument.php index dc9111f..7b4106f 100644 --- a/src/DocxDocument.php +++ b/src/DocxDocument.php @@ -24,6 +24,8 @@ class DocxDocument private $tempDocumentRelations = []; private $tempDocumentContentTypes = ''; private $tempDocumentNewImages = []; + private $tempDocumentHeaders = []; + private $tempDocumentFooters = []; /** * Construct an instance of Document @@ -58,6 +60,17 @@ private function extract(): void $this->zipClass->open($this->path); $this->zipClass->extractTo($this->tmpDir); + $index = 1; + while (false !== $this->zipClass->locateName($this->getHeaderName($index))) { + $this->tempDocumentHeaders[$index] = $this->readPartWithRels($this->getHeaderName($index)); + $index++; + } + $index = 1; + while (false !== $this->zipClass->locateName($this->getFooterName($index))) { + $this->tempDocumentFooters[$index] = $this->readPartWithRels($this->getFooterName($index)); + $index++; + } + $this->tempDocumentMainPart = $this->readPartWithRels($this->getMainPartName()); $this->tempDocumentContentTypes = $this->zipClass->getFromName($this->getDocumentContentTypesName()); @@ -75,6 +88,32 @@ public function getDocumentMainPart(): string return $this->tempDocumentMainPart; } + /** + * @return array + */ + public function getHeaders(): array + { + return $this->tempDocumentHeaders; + } + + /** + * @return array + */ + public function getFooters(): array + { + return $this->tempDocumentFooters; + } + + public function setHeaders(array $headers): void + { + $this->tempDocumentHeaders = $headers; + } + + public function setFooters(array $footers): void + { + $this->tempDocumentFooters = $footers; + } + /** * Get the name of main part document (method from PhpOffice\PhpWord) * @@ -636,6 +675,13 @@ public function save(string $path): void $this->savePartWithRels($this->getMainPartName()); file_put_contents($this->tmpDir . DIRECTORY_SEPARATOR . $this->getDocumentContentTypesName(), $this->tempDocumentContentTypes); + foreach ($this->tempDocumentHeaders as $index => $xml) { + file_put_contents($this->tmpDir . DIRECTORY_SEPARATOR . $this->getHeaderName($index), $xml); + } + foreach ($this->tempDocumentFooters as $index => $xml) { + file_put_contents($this->tmpDir . DIRECTORY_SEPARATOR . $this->getFooterName($index), $xml); + } + $files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($rootPath), RecursiveIteratorIterator::LEAVES_ONLY diff --git a/src/PhpDocxTemplate.php b/src/PhpDocxTemplate.php index 222f687..6d72a38 100644 --- a/src/PhpDocxTemplate.php +++ b/src/PhpDocxTemplate.php @@ -429,7 +429,6 @@ private function renderXml(string $srcXml, array $context): string ); $template->addExtension($ext); - $dstXml = $template->render('index', $context); $dstXml = str_replace( @@ -476,6 +475,9 @@ public function render(array $context): void $xmlSrc = $this->buildXml($context); $newXml = $this->docx->fixTables($xmlSrc); $this->updateXml($newXml); + + $this->renderHeaders($context); + $this->renderFooters($context); } /** @@ -490,6 +492,20 @@ public function save(string $path): void //$this->postProcessing($path); } + public function renderHeaders(array $context): void + { + $this->docx->setHeaders(array_map(function ($header) use ($context) { + return $this->renderXml($header, $context); + }, $this->docx->getHeaders())); + } + + public function renderFooters(array $context): void + { + $this->docx->setFooters(array_map(function ($footer) use ($context) { + return $this->renderXml($footer, $context); + }, $this->docx->getFooters())); + } + /** * Clean everything after rendering */ diff --git a/tests/PhpDocxTemplateTest.php b/tests/PhpDocxTemplateTest.php index 0ff08e4..066de7e 100644 --- a/tests/PhpDocxTemplateTest.php +++ b/tests/PhpDocxTemplateTest.php @@ -18,6 +18,7 @@ class PhpDocxTemplateTest extends TestCase private const TEMPLATE4 = __DIR__ . "/templates/template4.docx"; private const TEMPLATE5 = __DIR__ . "/templates/template5.docx"; private const TEMPLATE8 = __DIR__ . "/templates/template8.docx"; + private const TEMPLATE9 = __DIR__ . "/templates/template9.docx"; public function testXmlToString(): void { @@ -749,4 +750,91 @@ public function testImages(): void $this->assertNotEmpty($expectedImage, 'Embed image doesn\'t found.'); } + + public function testSections(): void + { + $reporter = new PhpDocxTemplate(self::TEMPLATE9); + /* $this->assertEquals( + $reporter->buildXml(["object" => "world"]), + "\n" . + "" . + "Hello world!" . + "" . + "" . + "" . + "\n" + );*/ + $docName = './doc9.docx'; + $reporter->render(["object" => "test", "section" => [["id" => "test section"]]]); + $reporter->save($docName); + // $reporter->close(); + + $expectedDocumentZip = new ZipArchive(); + $expectedDocumentZip->open($docName); + $header = $expectedDocumentZip->getFromName('word/header2.xml'); + $this->assertEquals('' . PHP_EOL . +'Opa test section', $header); + } } diff --git a/tests/templates/image.docx b/tests/templates/image.docx index 59546502d2c3685e8a7f786b66920994d7062c30..16baf07ad16173a012ef910ab53db8dc6a8608be 100644 GIT binary patch delta 2119 zcmZXV2|Qcb8o(2=*It*}Ycx92V)S(x70XzfA@f9$XlZP%-=oEtCI}4?2CdSfGPg|8 zQF%gY9~7}vEA8Vkzea0)=rU@FSXxU;HSb1vGo5$t?|<((-}%n@?)kp&oRgeNsHPKC zJg^99O_&r+9!BthfF$3Pxt1eQBAQwPhln3{VqtBYAf9yINW`%{l8;74CB3u6|^b>F)PFkU#OHTKbl^K?d0xB|XqnL@q8 zrMPe%(X`YyEvzjg(U8d==1eWE+S+B{SiB2@Akbx`i9;$UHynGpEZtru$a;j4C6Qiu znW6PF!D;tqJMeYm@9JBV=er3PT_IysAH6=1GWMpUtir9!P0-KIy<+la*$P@*=ZN}R zMyBfXHp5C!eXh}{7VbqqxNwzl{p|uc=z(EX@Op?5zbZC;QdYpnFIBAt9Ploecy|U_ z=wLZ3-5%?kl2zI|atj6(R~L8ZD#yTNNrs6f;t*ep?$Y2x;pM}@Dge+0i<1DAo%j~+ z#JAv~#-sgEe9J_l-dVcgjK}forUTzl$}+G0v(82R$c;CY`R@0V_Ale(-E?NmLhhF3 z(ThA~{e^4$QuLpmGUoY=e&9F9hRu~92xN!yFS5tfg$MIvO#r_-lLLYjEunKSl9H>d6oRbClN zLuJ{#qkNoLbWuGN&f@Xn6flShVs)zh*`T@d(pN)PT<)2mkJRFe9YHZlrnJt`?s=k1 zf*Hs1)%)^@fZ1ahC~3m={I}jNaaV>tkf`{j!&#M6g%e)Vu=+!#1 zh%kG2Gv%I~P4cw$p^=VJl$GepVjO%u__8apSt#QrdYIUChZH4aC3qlz3 zH!cldI@{BoZgvapf0X-k@0V8Xk26i4dzqQ&RXq3Valn}&Y?(?cc}JFH&-pU4G1`8h zKNZlHY+basruh%R?&)D!Q8cfut_TxS4!{8M_T8JV;iL$$2SN!#8A1g@6+#U{9YOUqr*3#B-z+bl0X{#{%&euZ#>?wXzdWTV9|8a8DW&z+F%-Up+5Ul^)t?e$ip~0#>xL2 z8f={y$XJXJZJfD!9~I3>=U_G&6TC)DP8z2wGxcd@Zn94rKPtG1Ktm;@JjpB`aSvtq zA-ln+{B!K)TD7xyUcKc+%1{r#(T?E27`2H;=ege5f7cDWi7YZ2KF-1!647&NAG}{1 z@~Ut4haDO@Wyet4@LMpEGfP`Ly%x_qvr%X9%Q(_^^_f2F(gSw~MyXEq-+Z^8vG-6l zCvh!0xC~}YAA zp8u=D6LU?O$<3;JK>VHH`ecZ_vQ>S#RY zdV!jr%UH~byqbh+BNH}F;ds=o$h+UQ(2vZ@_LS-g5eb1wEFYJk2{3>PXh~8fVIN=| zqym?+NBnW!fHuj1?m=0lM&$Ac_X;-?j_7iv{Cg7!5F&2nxi4Z@~r{U@Q@Qq64~!6-Px-FB#A` z79Ucs`((Z{h79S+!eIL1-`gpr^a3ZvoOuIKln5wE2Dc?agIApu!K7|Y09=Gx+cSK2 zlkEKuiZ zhY-r`0pU)HTA*?gApbuje{8G28gbMCBnz;Id?8sFQS23}-j4hx9Z=Jhf!qOusX)&X L0tPFm0#NI}KhS~? delta 2713 zcmZXW3pfsM7b0SVdc(VQh8mHT4W-U%VyaK zrCt7&ODNI`QF(hqsEA&9QS{&pe-VX6F39Gv}Q7KEHEr$5PJ5QE+x7l!z>V z1Ta8Ubhcw!6ym7}!FwZ_$01^!5KEVLERngQBEr^lpV0B2&!bDKvQXqutQ7z=*Yls z4weDnLwIXZ)~3Zk0ssREm8WApn8+GJADncb-S4||Fx#|U55e~H^E&ezR3vs|s7pQXFgO8-bmuh!A*2pZWhxsZFMkYk&p zGJ&}b;K-T{Jqcb>b5yU|%3wn56_eP){2|+Id&y(Nv@fGa#l>5hMG60v8zvb<|8@4h z_VKVrSG(Z1>jZg;r3seq1WtijXTZZh3wjzI!@?Uc^o=lmVt0)d9Mf8@)1mrgtn9XEM`pB`0&p+O( z(WkY#P%;{p@Kj+rDG{Cb5AaG ztSZ7pYznae*e*wTr5PYI(@o++2Om|`sE z;)w+^F{jOf!VKlxNto@rlHUuSIgR+GQ2CMlHlMc14;azi8kh#WN_2;&=U`DB8pKS> z2;vUghc+U!L04qphzaJZ;pC;7whb!gzTz=v54v?ZUk^wYN6A&q#$PY5jXf3H%aXAq{>e?6}M& z$0+9{98Mvsx1;t@kitcGmD3*uC*}#I3N4jm=;m_cMu(E|%MJ=zaehwf zjgU$1>o$lpA~tI)iO_tSpHZ=U0E5a;Pv-t9L12amh+KuR(v&Z2Uc90>y7ZHLZG0;| zWlCOT5xN)ZraT*WsKovIzWc!z_ezJPeAhup3KYc!vksD@*E45^ z=9x)YWN`)28MS^W@?-p)+G6sh)Wq`CoXBK@KiuWsnC@0;pirT6)sB6KqZ1G7%u?hy zGd>$9HS+M6az*z3+YUYm4eMfj>o%7-V5^=!+qu2Dnn8$BRH{-wPN)Rs4k~&TH@VuR+D=(i53qlvvuM-$v%wKta=*EPWpg!R#(Ltr#?l zdKAU6t(~yUZfHH9oqg^$C0nL1t-bL8f+ZNq9Kcv5sU&b>Mp&Dj`k4fff5fa)ASwu| zYOCJ9ORYX#ZB)u)L&?3mZ7e>9PJ2#EdOC2N-co^!JyA8#O_|Wiux^$mRNGT@51Rxw z*Az{4NnP-J_o(T!dsva_<-iI`O+93v8QxUP|5$oYPE)dKqCt?)b1AsnOu1R!joEVy zcZhdnf!LC%`$Rs@z!0O!&luw|JWpr zSJA;t^_*m*;Y=>X+MY{uY~m96gY=ntWu~IEiu}e@4=$gI<#oz_HuxyUGXCCg zk8YTCE2(;SZPlo>p{veR10qk#*SvV#<-7n(AQzfXr@hXh6=h0a84MU>dl#0L_TbN! zHWoW-tC|LIxX{~D`O{mT?=iIz)o-QVAL93>NmY$TL|Ce_o|Gm>NWY8G*ZB}_bwfKu zpZSrYk)V17&$`)bz}sisN6a`gF(#!JY6((5lmx6ceymQ<>YC>prDTnE$l@NKyJcQ! zj1`q7iCw1W7Vl~Z{t&+FYE1qUR@3~p8lLr?@W(N)IS0+VCAU?ss)Z!hglyMGn{Uc= zU3juH+rK!vLiLq$``0mLV3!})4j*X@+WThcEa%Ki7? zZAYs2wF3V|vw6|fk+j9oga?pB)^!JMZ+#Q%tnNK3fh_p z2AtAX+JO0W@1^MgnZI3rSWvj;Lr5Yvf60s$IClgNf!vGwwOxSbXrO|s(37W9_5PD4q)x3l%Ldo?pIcY5LEm8vjSEz+U~cggXlB?$<%rekrC)frGiZRLXVyFl&9vVaFq+fwYWCFu9q3=kCd2NbSKKVqND zt@j)E001e^-(!R1mt)HmLEQfhU`1M4G3M;3WgVPmRxb_U$HXtd6OZzzfsi5tR3Zt- zw6(>aX^a4Xeh~n`uXu+v9Rys7L4l#(fuZi?D5`hJQN753Q+6a#F<~4IJ||EBKw}91 G*#7_xRaqqf diff --git a/tests/templates/template9.docx b/tests/templates/template9.docx new file mode 100644 index 0000000000000000000000000000000000000000..40804257185a0b0c224639643195d133217a4062 GIT binary patch literal 19498 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 literal 0 HcmV?d00001